1 /*
2  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3  * Copyright (C) 2012 Google Inc. All Rights Reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  */
27 
28 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
29 
30 #include "base/metrics/histogram_macros.h"
31 #include "third_party/blink/public/common/feature_policy/document_policy_features.h"
32 #include "third_party/blink/public/mojom/feature_policy/feature_policy_feature.mojom-blink.h"
33 #include "third_party/blink/public/mojom/feature_policy/policy_disposition.mojom-blink.h"
34 #include "third_party/blink/public/platform/task_type.h"
35 #include "third_party/blink/renderer/bindings/core/v8/source_location.h"
36 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
37 #include "third_party/blink/renderer/core/dom/events/event_target.h"
38 #include "third_party/blink/renderer/core/events/error_event.h"
39 #include "third_party/blink/renderer/core/execution_context/agent.h"
40 #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_state_observer.h"
41 #include "third_party/blink/renderer/core/fileapi/public_url_manager.h"
42 #include "third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.h"
43 #include "third_party/blink/renderer/core/inspector/console_message.h"
44 #include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h"
45 #include "third_party/blink/renderer/core/probe/core_probes.h"
46 #include "third_party/blink/renderer/core/script/fetch_client_settings_object_impl.h"
47 #include "third_party/blink/renderer/core/workers/worker_global_scope.h"
48 #include "third_party/blink/renderer/core/workers/worker_thread.h"
49 #include "third_party/blink/renderer/platform/heap/heap.h"
50 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
51 #include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h"
52 #include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h"
53 #include "third_party/blink/renderer/platform/scheduler/public/event_loop.h"
54 #include "third_party/blink/renderer/platform/weborigin/security_policy.h"
55 
56 namespace blink {
57 
ExecutionContext(v8::Isolate * isolate)58 ExecutionContext::ExecutionContext(v8::Isolate* isolate)
59     : isolate_(isolate),
60       circular_sequential_id_(0),
61       in_dispatch_error_event_(false),
62       lifecycle_state_(mojom::FrameLifecycleState::kRunning),
63       is_context_destroyed_(false),
64       csp_delegate_(MakeGarbageCollected<ExecutionContextCSPDelegate>(*this)),
65       window_interaction_tokens_(0),
66       referrer_policy_(network::mojom::ReferrerPolicy::kDefault) {}
67 
68 ExecutionContext::~ExecutionContext() = default;
69 
70 // static
From(const ScriptState * script_state)71 ExecutionContext* ExecutionContext::From(const ScriptState* script_state) {
72   v8::HandleScope scope(script_state->GetIsolate());
73   return ToExecutionContext(script_state->GetContext());
74 }
75 
76 // static
From(v8::Local<v8::Context> context)77 ExecutionContext* ExecutionContext::From(v8::Local<v8::Context> context) {
78   return ToExecutionContext(context);
79 }
80 
81 // static
ForCurrentRealm(const v8::FunctionCallbackInfo<v8::Value> & info)82 ExecutionContext* ExecutionContext::ForCurrentRealm(
83     const v8::FunctionCallbackInfo<v8::Value>& info) {
84   return ToExecutionContext(info.GetIsolate()->GetCurrentContext());
85 }
86 
87 // static
ForRelevantRealm(const v8::FunctionCallbackInfo<v8::Value> & info)88 ExecutionContext* ExecutionContext::ForRelevantRealm(
89     const v8::FunctionCallbackInfo<v8::Value>& info) {
90   return ToExecutionContext(info.Holder()->CreationContext());
91 }
92 
SetLifecycleState(mojom::FrameLifecycleState state)93 void ExecutionContext::SetLifecycleState(mojom::FrameLifecycleState state) {
94   DCHECK(lifecycle_state_ != state);
95   lifecycle_state_ = state;
96   context_lifecycle_observer_list_.ForEachObserver(
97       [&](ContextLifecycleObserver* observer) {
98         if (!observer->IsExecutionContextLifecycleObserver())
99           return;
100         ExecutionContextLifecycleObserver* execution_context_observer =
101             static_cast<ExecutionContextLifecycleObserver*>(observer);
102         if (execution_context_observer->ObserverType() !=
103             ExecutionContextLifecycleObserver::kStateObjectType)
104           return;
105         ExecutionContextLifecycleStateObserver* state_observer =
106             static_cast<ExecutionContextLifecycleStateObserver*>(
107                 execution_context_observer);
108 #if DCHECK_IS_ON()
109         DCHECK_EQ(state_observer->GetExecutionContext(), this);
110         DCHECK(state_observer->UpdateStateIfNeededCalled());
111 #endif
112         state_observer->ContextLifecycleStateChanged(state);
113       });
114 }
115 
NotifyContextDestroyed()116 void ExecutionContext::NotifyContextDestroyed() {
117   is_context_destroyed_ = true;
118   context_lifecycle_observer_list_.ForEachObserver(
119       [](ContextLifecycleObserver* observer) {
120         observer->ContextDestroyed();
121         observer->ObserverListWillBeCleared();
122       });
123   context_lifecycle_observer_list_.Clear();
124 }
125 
AddContextLifecycleObserver(ContextLifecycleObserver * observer)126 void ExecutionContext::AddContextLifecycleObserver(
127     ContextLifecycleObserver* observer) {
128   context_lifecycle_observer_list_.AddObserver(observer);
129 }
130 
RemoveContextLifecycleObserver(ContextLifecycleObserver * observer)131 void ExecutionContext::RemoveContextLifecycleObserver(
132     ContextLifecycleObserver* observer) {
133   DCHECK(context_lifecycle_observer_list_.HasObserver(observer));
134   context_lifecycle_observer_list_.RemoveObserver(observer);
135 }
136 
ContextLifecycleStateObserverCountForTesting() const137 unsigned ExecutionContext::ContextLifecycleStateObserverCountForTesting()
138     const {
139   DCHECK(!context_lifecycle_observer_list_.IsIteratingOverObservers());
140   unsigned lifecycle_state_observers = 0;
141   context_lifecycle_observer_list_.ForEachObserver(
142       [&](ContextLifecycleObserver* observer) {
143         if (!observer->IsExecutionContextLifecycleObserver())
144           return;
145         if (static_cast<ExecutionContextLifecycleObserver*>(observer)
146                 ->ObserverType() !=
147             ExecutionContextLifecycleObserver::kStateObjectType)
148           return;
149         lifecycle_state_observers++;
150       });
151   return lifecycle_state_observers;
152 }
153 
AddConsoleMessageImpl(mojom::ConsoleMessageSource source,mojom::ConsoleMessageLevel level,const String & message,bool discard_duplicates)154 void ExecutionContext::AddConsoleMessageImpl(mojom::ConsoleMessageSource source,
155                                              mojom::ConsoleMessageLevel level,
156                                              const String& message,
157                                              bool discard_duplicates) {
158   AddConsoleMessage(
159       MakeGarbageCollected<ConsoleMessage>(source, level, message),
160       discard_duplicates);
161 }
162 
DispatchErrorEvent(ErrorEvent * error_event,SanitizeScriptErrors sanitize_script_errors)163 void ExecutionContext::DispatchErrorEvent(
164     ErrorEvent* error_event,
165     SanitizeScriptErrors sanitize_script_errors) {
166   if (in_dispatch_error_event_) {
167     pending_exceptions_.push_back(error_event);
168     return;
169   }
170 
171   // First report the original exception and only then all the nested ones.
172   if (!DispatchErrorEventInternal(error_event, sanitize_script_errors))
173     ExceptionThrown(error_event);
174 
175   if (pending_exceptions_.IsEmpty())
176     return;
177   for (ErrorEvent* e : pending_exceptions_)
178     ExceptionThrown(e);
179   pending_exceptions_.clear();
180 }
181 
DispatchErrorEventInternal(ErrorEvent * error_event,SanitizeScriptErrors sanitize_script_errors)182 bool ExecutionContext::DispatchErrorEventInternal(
183     ErrorEvent* error_event,
184     SanitizeScriptErrors sanitize_script_errors) {
185   EventTarget* target = ErrorEventTarget();
186   if (!target)
187     return false;
188 
189   if (sanitize_script_errors == SanitizeScriptErrors::kSanitize) {
190     error_event = ErrorEvent::CreateSanitizedError(
191         ToScriptState(this, *error_event->World()));
192   }
193 
194   DCHECK(!in_dispatch_error_event_);
195   in_dispatch_error_event_ = true;
196   target->DispatchEvent(*error_event);
197   in_dispatch_error_event_ = false;
198   return error_event->defaultPrevented();
199 }
200 
IsContextPaused() const201 bool ExecutionContext::IsContextPaused() const {
202   return lifecycle_state_ != mojom::FrameLifecycleState::kRunning;
203 }
204 
CircularSequentialID()205 int ExecutionContext::CircularSequentialID() {
206   ++circular_sequential_id_;
207   if (circular_sequential_id_ > ((1U << 31) - 1U))
208     circular_sequential_id_ = 1;
209 
210   return circular_sequential_id_;
211 }
212 
GetPublicURLManager()213 PublicURLManager& ExecutionContext::GetPublicURLManager() {
214   if (!public_url_manager_)
215     public_url_manager_ = MakeGarbageCollected<PublicURLManager>(this);
216   return *public_url_manager_;
217 }
218 
219 ContentSecurityPolicyDelegate&
GetContentSecurityPolicyDelegate()220 ExecutionContext::GetContentSecurityPolicyDelegate() {
221   return *csp_delegate_;
222 }
223 
GetContentSecurityPolicyForWorld()224 ContentSecurityPolicy* ExecutionContext::GetContentSecurityPolicyForWorld() {
225   // Isolated worlds are only relevant for Documents. Hence just return the main
226   // world's content security policy by default.
227   return GetContentSecurityPolicy();
228 }
229 
GetSecurityOrigin() const230 const SecurityOrigin* ExecutionContext::GetSecurityOrigin() const {
231   return GetSecurityContext().GetSecurityOrigin();
232 }
233 
GetMutableSecurityOrigin()234 SecurityOrigin* ExecutionContext::GetMutableSecurityOrigin() {
235   return GetSecurityContext().GetMutableSecurityOrigin();
236 }
237 
GetContentSecurityPolicy() const238 ContentSecurityPolicy* ExecutionContext::GetContentSecurityPolicy() const {
239   return GetSecurityContext().GetContentSecurityPolicy();
240 }
241 
GetSandboxFlags() const242 mojom::blink::WebSandboxFlags ExecutionContext::GetSandboxFlags() const {
243   return GetSecurityContext().GetSandboxFlags();
244 }
245 
IsSandboxed(mojom::blink::WebSandboxFlags mask) const246 bool ExecutionContext::IsSandboxed(mojom::blink::WebSandboxFlags mask) const {
247   return GetSecurityContext().IsSandboxed(mask);
248 }
249 
GetAgentClusterID() const250 const base::UnguessableToken& ExecutionContext::GetAgentClusterID() const {
251   return GetAgent()->cluster_id();
252 }
253 
AllowWindowInteraction()254 void ExecutionContext::AllowWindowInteraction() {
255   ++window_interaction_tokens_;
256 }
257 
ConsumeWindowInteraction()258 void ExecutionContext::ConsumeWindowInteraction() {
259   if (window_interaction_tokens_ == 0)
260     return;
261   --window_interaction_tokens_;
262 }
263 
IsWindowInteractionAllowed() const264 bool ExecutionContext::IsWindowInteractionAllowed() const {
265   return window_interaction_tokens_ > 0;
266 }
267 
IsSecureContext(String & error_message) const268 bool ExecutionContext::IsSecureContext(String& error_message) const {
269   if (!IsSecureContext()) {
270     error_message = SecurityOrigin::IsPotentiallyTrustworthyErrorMessage();
271     return false;
272   }
273   return true;
274 }
275 
276 // https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer
OutgoingReferrer() const277 String ExecutionContext::OutgoingReferrer() const {
278   // Step 3.1: "If environment's global object is a Window object, then"
279   // This case is implemented in Document::OutgoingReferrer().
280 
281   // Step 3.2: "Otherwise, let referrerSource be environment's creation URL."
282   return Url().StrippedForUseAsReferrer();
283 }
284 
ParseAndSetReferrerPolicy(const String & policies,bool support_legacy_keywords)285 void ExecutionContext::ParseAndSetReferrerPolicy(const String& policies,
286                                                  bool support_legacy_keywords) {
287   network::mojom::ReferrerPolicy referrer_policy;
288 
289   if (!SecurityPolicy::ReferrerPolicyFromHeaderValue(
290           policies,
291           support_legacy_keywords ? kSupportReferrerPolicyLegacyKeywords
292                                   : kDoNotSupportReferrerPolicyLegacyKeywords,
293           &referrer_policy)) {
294     AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
295         mojom::ConsoleMessageSource::kRendering,
296         mojom::ConsoleMessageLevel::kError,
297         "Failed to set referrer policy: The value '" + policies +
298             "' is not one of " +
299             (support_legacy_keywords
300                  ? "'always', 'default', 'never', 'origin-when-crossorigin', "
301                  : "") +
302             "'no-referrer', 'no-referrer-when-downgrade', 'origin', "
303             "'origin-when-cross-origin', 'same-origin', 'strict-origin', "
304             "'strict-origin-when-cross-origin', or 'unsafe-url'. The referrer "
305             "policy "
306             "has been left unchanged."));
307     return;
308   }
309 
310   SetReferrerPolicy(referrer_policy);
311 }
312 
SetReferrerPolicy(network::mojom::ReferrerPolicy referrer_policy)313 void ExecutionContext::SetReferrerPolicy(
314     network::mojom::ReferrerPolicy referrer_policy) {
315   // When a referrer policy has already been set, the latest value takes
316   // precedence.
317   UseCounter::Count(this, WebFeature::kSetReferrerPolicy);
318   if (referrer_policy_ != network::mojom::ReferrerPolicy::kDefault)
319     UseCounter::Count(this, WebFeature::kResetReferrerPolicy);
320 
321   referrer_policy_ = referrer_policy;
322 }
323 
RemoveURLFromMemoryCache(const KURL & url)324 void ExecutionContext::RemoveURLFromMemoryCache(const KURL& url) {
325   GetMemoryCache()->RemoveURLFromCache(url);
326 }
327 
Trace(Visitor * visitor)328 void ExecutionContext::Trace(Visitor* visitor) {
329   visitor->Trace(public_url_manager_);
330   visitor->Trace(pending_exceptions_);
331   visitor->Trace(csp_delegate_);
332   visitor->Trace(timers_);
333   visitor->Trace(context_lifecycle_observer_list_);
334   ContextLifecycleNotifier::Trace(visitor);
335   ConsoleLogger::Trace(visitor);
336   Supplementable<ExecutionContext>::Trace(visitor);
337 }
338 
IsSameAgentCluster(const base::UnguessableToken & other_id) const339 bool ExecutionContext::IsSameAgentCluster(
340     const base::UnguessableToken& other_id) const {
341   base::UnguessableToken this_id = GetAgentClusterID();
342   // If the AgentClusterID is empty then it should never be the same (e.g.
343   // currently for worklets).
344   if (this_id.is_empty() || other_id.is_empty())
345     return false;
346   return this_id == other_id;
347 }
348 
GetMicrotaskQueue() const349 v8::MicrotaskQueue* ExecutionContext::GetMicrotaskQueue() const {
350   // TODO(keishi): Convert to DCHECK once we assign agents everywhere.
351   if (!GetAgent())
352     return nullptr;
353   DCHECK(GetAgent()->event_loop());
354   return GetAgent()->event_loop()->microtask_queue();
355 }
356 
FeatureEnabled(OriginTrialFeature feature) const357 bool ExecutionContext::FeatureEnabled(OriginTrialFeature feature) const {
358   return GetOriginTrialContext() &&
359          GetOriginTrialContext()->IsFeatureEnabled(feature);
360 }
361 
CountFeaturePolicyUsage(mojom::WebFeature feature)362 void ExecutionContext::CountFeaturePolicyUsage(mojom::WebFeature feature) {
363   UseCounter::Count(*this, feature);
364 }
365 
FeaturePolicyFeatureObserved(mojom::blink::FeaturePolicyFeature feature)366 bool ExecutionContext::FeaturePolicyFeatureObserved(
367     mojom::blink::FeaturePolicyFeature feature) {
368   size_t feature_index = static_cast<size_t>(feature);
369   if (parsed_feature_policies_.size() == 0) {
370     parsed_feature_policies_.resize(
371         static_cast<size_t>(mojom::blink::FeaturePolicyFeature::kMaxValue) + 1);
372   } else if (parsed_feature_policies_[feature_index]) {
373     return true;
374   }
375   parsed_feature_policies_[feature_index] = true;
376   return false;
377 }
378 
FeaturePolicyPotentialBehaviourChangeObserved(mojom::blink::FeaturePolicyFeature feature) const379 void ExecutionContext::FeaturePolicyPotentialBehaviourChangeObserved(
380     mojom::blink::FeaturePolicyFeature feature) const {
381   size_t feature_index = static_cast<size_t>(feature);
382   if (feature_policy_behaviour_change_counted_.size() == 0) {
383     feature_policy_behaviour_change_counted_.resize(
384         static_cast<size_t>(mojom::blink::FeaturePolicyFeature::kMaxValue) + 1);
385   } else if (feature_policy_behaviour_change_counted_[feature_index]) {
386     return;
387   }
388   feature_policy_behaviour_change_counted_[feature_index] = true;
389   UMA_HISTOGRAM_ENUMERATION(
390       "Blink.UseCounter.FeaturePolicy.ProposalWouldChangeBehaviour", feature);
391 }
392 
IsFeatureEnabled(mojom::blink::FeaturePolicyFeature feature,ReportOptions report_on_failure,const String & message,const String & source_file) const393 bool ExecutionContext::IsFeatureEnabled(
394     mojom::blink::FeaturePolicyFeature feature,
395     ReportOptions report_on_failure,
396     const String& message,
397     const String& source_file) const {
398   PolicyValue threshold_value =
399       PolicyValue::CreateMaxPolicyValue(GetSecurityContext()
400                                             .GetFeaturePolicy()
401                                             ->GetFeatureList()
402                                             .at(feature)
403                                             .second);
404   return IsFeatureEnabled(feature, threshold_value, report_on_failure, message,
405                           source_file);
406 }
407 
IsFeatureEnabled(mojom::blink::FeaturePolicyFeature feature,PolicyValue threshold_value,ReportOptions report_on_failure,const String & message,const String & source_file) const408 bool ExecutionContext::IsFeatureEnabled(
409     mojom::blink::FeaturePolicyFeature feature,
410     PolicyValue threshold_value,
411     ReportOptions report_on_failure,
412     const String& message,
413     const String& source_file) const {
414   if (report_on_failure == ReportOptions::kReportOnFailure) {
415     // We are expecting a violation report in case the feature is disabled in
416     // the context. Therefore, this qualifies as a potential violation (i.e.,
417     // if the feature was disabled it would generate a report).
418     CountPotentialFeaturePolicyViolation(feature);
419   }
420 
421   bool should_report;
422   bool enabled = GetSecurityContext().IsFeatureEnabled(feature, threshold_value,
423                                                        &should_report);
424 
425   if (enabled) {
426     // Report if the proposed header semantics change would have affected the
427     // outcome. (https://crbug.com/937131)
428     const FeaturePolicy* policy = GetSecurityContext().GetFeaturePolicy();
429     url::Origin origin = GetSecurityOrigin()->ToUrlOrigin();
430     if (policy->GetProposedFeatureValueForOrigin(feature, origin) <
431         threshold_value) {
432       // Count that there was a change in this page load.
433       const_cast<ExecutionContext*>(this)->CountUse(
434           WebFeature::kFeaturePolicyProposalWouldChangeBehaviour);
435       // Record the specific feature whose behaviour was changed.
436       FeaturePolicyPotentialBehaviourChangeObserved(feature);
437     }
438   }
439 
440   if (should_report && report_on_failure == ReportOptions::kReportOnFailure) {
441     mojom::blink::PolicyDisposition disposition =
442         enabled ? mojom::blink::PolicyDisposition::kReport
443                 : mojom::blink::PolicyDisposition::kEnforce;
444     ReportFeaturePolicyViolation(feature, disposition, message, source_file);
445   }
446   return enabled;
447 }
448 
IsFeatureEnabled(mojom::blink::DocumentPolicyFeature feature,ReportOptions report_option,const String & message,const String & source_file) const449 bool ExecutionContext::IsFeatureEnabled(
450     mojom::blink::DocumentPolicyFeature feature,
451     ReportOptions report_option,
452     const String& message,
453     const String& source_file) const {
454   DCHECK(GetDocumentPolicyFeatureInfoMap().at(feature).default_value.Type() ==
455          mojom::blink::PolicyValueType::kBool);
456   return IsFeatureEnabled(feature, PolicyValue(true), report_option, message,
457                           source_file);
458 }
459 
IsFeatureEnabled(mojom::blink::DocumentPolicyFeature feature,PolicyValue threshold_value,ReportOptions report_option,const String & message,const String & source_file) const460 bool ExecutionContext::IsFeatureEnabled(
461     mojom::blink::DocumentPolicyFeature feature,
462     PolicyValue threshold_value,
463     ReportOptions report_option,
464     const String& message,
465     const String& source_file) const {
466   // The default value for any feature should be true unless restricted by
467   // document policy
468   if (!RuntimeEnabledFeatures::DocumentPolicyEnabled(this))
469     return true;
470 
471   SecurityContext::FeatureStatus status =
472       GetSecurityContext().IsFeatureEnabled(feature, threshold_value);
473   if (status.should_report &&
474       report_option == ReportOptions::kReportOnFailure) {
475     // If both |enabled| and |should_report| are true, the usage must have
476     // violated the report-only policy, i.e. |disposition| ==
477     // mojom::blink::PolicyDisposition::kReport.
478     ReportDocumentPolicyViolation(
479         feature,
480         status.enabled ? mojom::blink::PolicyDisposition::kReport
481                        : mojom::blink::PolicyDisposition::kEnforce,
482         message, source_file);
483   }
484   return status.enabled;
485 }
486 
RequireTrustedTypes() const487 bool ExecutionContext::RequireTrustedTypes() const {
488   return GetSecurityContext().TrustedTypesRequiredByPolicy() &&
489          RuntimeEnabledFeatures::TrustedDOMTypesEnabled(this);
490 }
491 
addressSpaceForBindings() const492 String ExecutionContext::addressSpaceForBindings() const {
493   switch (GetSecurityContext().AddressSpace()) {
494     case network::mojom::IPAddressSpace::kPublic:
495     case network::mojom::IPAddressSpace::kUnknown:
496       return "public";
497 
498     case network::mojom::IPAddressSpace::kPrivate:
499       return "private";
500 
501     case network::mojom::IPAddressSpace::kLocal:
502       return "local";
503   }
504   NOTREACHED();
505   return "public";
506 }
507 
508 }  // namespace blink
509