1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/dom/WorkerNavigator.h"
11 #include "ErrorList.h"
12 #include "MainThreadUtils.h"
13 #include "RuntimeService.h"
14 #include "WorkerRunnable.h"
15 #include "WorkerScope.h"
16 #include "mozilla/dom/LockManager.h"
17 #include "mozilla/dom/MediaCapabilities.h"
18 #include "mozilla/dom/Navigator.h"
19 #include "mozilla/dom/Permissions.h"
20 #include "mozilla/dom/ServiceWorkerContainer.h"
21 #include "mozilla/dom/StorageManager.h"
22 #include "mozilla/dom/WorkerCommon.h"
23 #include "mozilla/dom/WorkerNavigatorBinding.h"
24 #include "mozilla/dom/WorkerStatus.h"
25 #include "mozilla/dom/network/Connection.h"
26 #include "mozilla/webgpu/Instance.h"
30 #include "nsIGlobalObject.h"
31 #include "nsLiteralString.h"
32 #include "nsPIDOMWindow.h"
33 #include "nsRFPService.h"
39 namespace mozilla::dom
{
41 using namespace workerinternals
;
43 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(WorkerNavigator
)
44 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(WorkerNavigator
)
46 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
47 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
49 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(WorkerNavigator
)
50 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStorageManager
)
51 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection
)
52 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaCapabilities
)
53 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebGpu
)
54 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocks
)
55 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPermissions
)
56 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorkerContainer
)
57 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
59 WorkerNavigator::WorkerNavigator(const NavigatorProperties
& aProperties
,
61 : mProperties(aProperties
), mOnline(aOnline
) {}
63 WorkerNavigator::~WorkerNavigator() { Invalidate(); }
66 already_AddRefed
<WorkerNavigator
> WorkerNavigator::Create(bool aOnLine
) {
67 RuntimeService
* rts
= RuntimeService::GetService();
70 const RuntimeService::NavigatorProperties
& properties
=
71 rts
->GetNavigatorProperties();
73 RefPtr
<WorkerNavigator
> navigator
= new WorkerNavigator(properties
, aOnLine
);
75 return navigator
.forget();
78 void WorkerNavigator::Invalidate() {
79 if (mStorageManager
) {
80 mStorageManager
->Shutdown();
81 mStorageManager
= nullptr;
84 mConnection
= nullptr;
86 mMediaCapabilities
= nullptr;
95 mPermissions
= nullptr;
97 mServiceWorkerContainer
= nullptr;
100 JSObject
* WorkerNavigator::WrapObject(JSContext
* aCx
,
101 JS::Handle
<JSObject
*> aGivenProto
) {
102 return WorkerNavigator_Binding::Wrap(aCx
, this, aGivenProto
);
105 bool WorkerNavigator::GlobalPrivacyControl() const {
106 bool gpcStatus
= StaticPrefs::privacy_globalprivacycontrol_enabled();
108 JSObject
* jso
= GetWrapper();
109 if (const nsCOMPtr
<nsIGlobalObject
> global
= xpc::NativeGlobal(jso
)) {
110 if (const nsCOMPtr
<nsIPrincipal
> principal
= global
->PrincipalOrNull()) {
111 gpcStatus
= principal
->GetIsInPrivateBrowsing() &&
112 StaticPrefs::privacy_globalprivacycontrol_pbmode_enabled();
116 return StaticPrefs::privacy_globalprivacycontrol_functionality_enabled() &&
120 void WorkerNavigator::SetLanguages(const nsTArray
<nsString
>& aLanguages
) {
121 WorkerNavigator_Binding::ClearCachedLanguagesValue(this);
122 mProperties
.mLanguages
= aLanguages
.Clone();
125 void WorkerNavigator::GetAppVersion(nsString
& aAppVersion
,
126 CallerType aCallerType
,
127 ErrorResult
& aRv
) const {
128 WorkerPrivate
* workerPrivate
= GetCurrentThreadWorkerPrivate();
129 MOZ_ASSERT(workerPrivate
);
131 if (aCallerType
!= CallerType::System
) {
132 if (workerPrivate
->ShouldResistFingerprinting(
133 RFPTarget::NavigatorAppVersion
)) {
134 // See nsRFPService.h for spoofed value.
135 aAppVersion
.AssignLiteral(SPOOFED_APPVERSION
);
139 if (!mProperties
.mAppVersionOverridden
.IsEmpty()) {
140 aAppVersion
= mProperties
.mAppVersionOverridden
;
145 aAppVersion
= mProperties
.mAppVersion
;
148 void WorkerNavigator::GetPlatform(nsString
& aPlatform
, CallerType aCallerType
,
149 ErrorResult
& aRv
) const {
150 WorkerPrivate
* workerPrivate
= GetCurrentThreadWorkerPrivate();
151 MOZ_ASSERT(workerPrivate
);
153 // navigator.platform is the same for default and spoofed values. The
154 // "general.platform.override" pref should override the default platform,
155 // but the spoofed platform should override the pref.
156 if (aCallerType
== CallerType::System
||
157 workerPrivate
->ShouldResistFingerprinting(RFPTarget::NavigatorPlatform
) ||
158 mProperties
.mPlatformOverridden
.IsEmpty()) {
159 aPlatform
= mProperties
.mPlatform
;
161 // from "general.platform.override" pref.
162 aPlatform
= mProperties
.mPlatformOverridden
;
169 * This Worker Runnable needs to check RFP; but our standard way of doing so
170 * relies on accessing GlobalScope() - which can only be accessed on the worker
171 * thread. So we need to pass it in.
173 class GetUserAgentRunnable final
: public WorkerMainThreadRunnable
{
175 bool mShouldResistFingerprinting
;
178 GetUserAgentRunnable(WorkerPrivate
* aWorkerPrivate
, nsString
& aUA
,
179 bool aShouldResistFingerprinting
)
180 : WorkerMainThreadRunnable(aWorkerPrivate
, "UserAgent getter"_ns
),
182 mShouldResistFingerprinting(aShouldResistFingerprinting
) {
183 MOZ_ASSERT(aWorkerPrivate
);
184 aWorkerPrivate
->AssertIsOnWorkerThread();
187 virtual bool MainThreadRun() override
{
188 AssertIsOnMainThread();
189 MOZ_ASSERT(mWorkerRef
);
191 WorkerPrivate
* workerPrivate
= mWorkerRef
->Private();
193 nsCOMPtr
<nsPIDOMWindowInner
> window
= workerPrivate
->GetWindow();
196 dom::Navigator::GetUserAgent(window
, workerPrivate
->GetDocument(),
197 Some(mShouldResistFingerprinting
), mUA
);
199 NS_WARNING("Failed to retrieve user-agent from the worker thread.");
208 void WorkerNavigator::GetUserAgent(nsString
& aUserAgent
, CallerType aCallerType
,
209 ErrorResult
& aRv
) const {
210 WorkerPrivate
* workerPrivate
= GetCurrentThreadWorkerPrivate();
211 MOZ_ASSERT(workerPrivate
);
213 RefPtr
<GetUserAgentRunnable
> runnable
= new GetUserAgentRunnable(
214 workerPrivate
, aUserAgent
,
215 workerPrivate
->ShouldResistFingerprinting(RFPTarget::NavigatorUserAgent
));
217 runnable
->Dispatch(workerPrivate
, Canceling
, aRv
);
220 uint64_t WorkerNavigator::HardwareConcurrency() const {
221 RuntimeService
* rts
= RuntimeService::GetService();
224 WorkerPrivate
* aWorkerPrivate
= GetCurrentThreadWorkerPrivate();
225 bool rfp
= aWorkerPrivate
->ShouldResistFingerprinting(
226 RFPTarget::NavigatorHWConcurrency
);
228 return rts
->ClampedHardwareConcurrency(rfp
);
231 StorageManager
* WorkerNavigator::Storage() {
232 if (!mStorageManager
) {
233 WorkerPrivate
* workerPrivate
= GetCurrentThreadWorkerPrivate();
234 MOZ_ASSERT(workerPrivate
);
236 RefPtr
<nsIGlobalObject
> global
= workerPrivate
->GlobalScope();
239 mStorageManager
= new StorageManager(global
);
241 workerPrivate
->NotifyStorageKeyUsed();
244 return mStorageManager
;
247 network::Connection
* WorkerNavigator::GetConnection(ErrorResult
& aRv
) {
249 WorkerPrivate
* workerPrivate
= GetCurrentThreadWorkerPrivate();
250 MOZ_ASSERT(workerPrivate
);
252 mConnection
= network::Connection::CreateForWorker(workerPrivate
, aRv
);
258 dom::MediaCapabilities
* WorkerNavigator::MediaCapabilities() {
259 if (!mMediaCapabilities
) {
260 WorkerPrivate
* workerPrivate
= GetCurrentThreadWorkerPrivate();
261 MOZ_ASSERT(workerPrivate
);
263 nsIGlobalObject
* global
= workerPrivate
->GlobalScope();
266 mMediaCapabilities
= new dom::MediaCapabilities(global
);
268 return mMediaCapabilities
;
271 webgpu::Instance
* WorkerNavigator::Gpu() {
273 WorkerPrivate
* workerPrivate
= GetCurrentThreadWorkerPrivate();
274 MOZ_ASSERT(workerPrivate
);
276 nsIGlobalObject
* global
= workerPrivate
->GlobalScope();
279 mWebGpu
= webgpu::Instance::Create(global
);
284 dom::LockManager
* WorkerNavigator::Locks() {
286 WorkerPrivate
* workerPrivate
= GetCurrentThreadWorkerPrivate();
287 MOZ_ASSERT(workerPrivate
);
289 nsIGlobalObject
* global
= workerPrivate
->GlobalScope();
292 mLocks
= dom::LockManager::Create(*global
);
297 dom::Permissions
* WorkerNavigator::Permissions() {
299 WorkerPrivate
* workerPrivate
= GetCurrentThreadWorkerPrivate();
300 MOZ_ASSERT(workerPrivate
);
302 nsIGlobalObject
* global
= workerPrivate
->GlobalScope();
304 mPermissions
= new dom::Permissions(global
);
310 already_AddRefed
<ServiceWorkerContainer
> WorkerNavigator::ServiceWorker() {
311 if (!mServiceWorkerContainer
) {
312 WorkerPrivate
* workerPrivate
= GetCurrentThreadWorkerPrivate();
313 MOZ_ASSERT(workerPrivate
);
315 nsIGlobalObject
* global
= workerPrivate
->GlobalScope();
318 mServiceWorkerContainer
= ServiceWorkerContainer::Create(global
);
321 RefPtr
<ServiceWorkerContainer
> ref
= mServiceWorkerContainer
;
325 } // namespace mozilla::dom