WorkerNavigator.cpp (10033B)
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/. */ 6 7 #include "mozilla/dom/WorkerNavigator.h" 8 9 #include "ErrorList.h" 10 #include "MainThreadUtils.h" 11 #include "RuntimeService.h" 12 #include "WorkerRunnable.h" 13 #include "WorkerScope.h" 14 #include "mozilla/dom/LockManager.h" 15 #include "mozilla/dom/MediaCapabilities.h" 16 #include "mozilla/dom/Navigator.h" 17 #include "mozilla/dom/Permissions.h" 18 #include "mozilla/dom/ServiceWorkerContainer.h" 19 #include "mozilla/dom/StorageManager.h" 20 #include "mozilla/dom/WorkerCommon.h" 21 #include "mozilla/dom/WorkerNavigatorBinding.h" 22 #include "mozilla/dom/WorkerStatus.h" 23 #include "mozilla/dom/network/Connection.h" 24 #include "mozilla/webgpu/Instance.h" 25 #include "nsCOMPtr.h" 26 #include "nsDebug.h" 27 #include "nsError.h" 28 #include "nsIGlobalObject.h" 29 #include "nsLiteralString.h" 30 #include "nsPIDOMWindow.h" 31 #include "nsRFPService.h" 32 #include "nsString.h" 33 34 class JSObject; 35 struct JSContext; 36 37 namespace mozilla::dom { 38 39 using namespace workerinternals; 40 41 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(WorkerNavigator) 42 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(WorkerNavigator) 43 tmp->Invalidate(); 44 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER 45 NS_IMPL_CYCLE_COLLECTION_UNLINK_END 46 47 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(WorkerNavigator) 48 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStorageManager) 49 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection) 50 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaCapabilities) 51 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebGpu) 52 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocks) 53 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPermissions) 54 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorkerContainer) 55 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 56 57 WorkerNavigator::WorkerNavigator(const NavigatorProperties& aProperties, 58 bool aOnline) 59 : mProperties(aProperties), mOnline(aOnline) {} 60 61 WorkerNavigator::~WorkerNavigator() { Invalidate(); } 62 63 /* static */ 64 already_AddRefed<WorkerNavigator> WorkerNavigator::Create(bool aOnLine) { 65 RuntimeService* rts = RuntimeService::GetService(); 66 MOZ_ASSERT(rts); 67 68 const RuntimeService::NavigatorProperties& properties = 69 rts->GetNavigatorProperties(); 70 71 RefPtr<WorkerNavigator> navigator = new WorkerNavigator(properties, aOnLine); 72 73 return navigator.forget(); 74 } 75 76 void WorkerNavigator::Invalidate() { 77 if (mStorageManager) { 78 mStorageManager->Shutdown(); 79 mStorageManager = nullptr; 80 } 81 82 mConnection = nullptr; 83 84 mMediaCapabilities = nullptr; 85 86 mWebGpu = nullptr; 87 88 if (mLocks) { 89 mLocks->Shutdown(); 90 mLocks = nullptr; 91 } 92 93 mPermissions = nullptr; 94 95 mServiceWorkerContainer = nullptr; 96 } 97 98 JSObject* WorkerNavigator::WrapObject(JSContext* aCx, 99 JS::Handle<JSObject*> aGivenProto) { 100 return WorkerNavigator_Binding::Wrap(aCx, this, aGivenProto); 101 } 102 103 bool WorkerNavigator::GlobalPrivacyControl() const { 104 bool gpcStatus = StaticPrefs::privacy_globalprivacycontrol_enabled(); 105 if (!gpcStatus) { 106 JSObject* jso = GetWrapper(); 107 if (const nsCOMPtr<nsIGlobalObject> global = xpc::NativeGlobal(jso)) { 108 if (const nsCOMPtr<nsIPrincipal> principal = global->PrincipalOrNull()) { 109 gpcStatus = principal->GetIsInPrivateBrowsing() && 110 StaticPrefs::privacy_globalprivacycontrol_pbmode_enabled(); 111 } 112 } 113 } 114 return StaticPrefs::privacy_globalprivacycontrol_functionality_enabled() && 115 gpcStatus; 116 } 117 118 void WorkerNavigator::SetLanguages(const nsTArray<nsString>& aLanguages) { 119 WorkerNavigator_Binding::ClearCachedLanguagesValue(this); 120 mProperties.mLanguages = aLanguages.Clone(); 121 } 122 123 void WorkerNavigator::GetAppVersion(nsString& aAppVersion, 124 CallerType aCallerType, 125 ErrorResult& aRv) const { 126 WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); 127 MOZ_ASSERT(workerPrivate); 128 129 if (aCallerType != CallerType::System) { 130 if (workerPrivate->ShouldResistFingerprinting( 131 RFPTarget::NavigatorAppVersion)) { 132 // See nsRFPService.h for spoofed value. 133 aAppVersion.AssignLiteral(SPOOFED_APPVERSION); 134 return; 135 } 136 137 if (!mProperties.mAppVersionOverridden.IsEmpty()) { 138 aAppVersion = mProperties.mAppVersionOverridden; 139 return; 140 } 141 } 142 143 aAppVersion = mProperties.mAppVersion; 144 } 145 146 void WorkerNavigator::GetPlatform(nsString& aPlatform, CallerType aCallerType, 147 ErrorResult& aRv) const { 148 WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); 149 MOZ_ASSERT(workerPrivate); 150 151 // navigator.platform is the same for default and spoofed values. The 152 // "general.platform.override" pref should override the default platform, 153 // but the spoofed platform should override the pref. 154 if (aCallerType == CallerType::System || 155 workerPrivate->ShouldResistFingerprinting(RFPTarget::NavigatorPlatform) || 156 mProperties.mPlatformOverridden.IsEmpty()) { 157 aPlatform = mProperties.mPlatform; 158 } else { 159 // from "general.platform.override" pref. 160 aPlatform = mProperties.mPlatformOverridden; 161 } 162 } 163 164 namespace { 165 166 /* 167 * This Worker Runnable needs to check RFP; but our standard way of doing so 168 * relies on accessing GlobalScope() - which can only be accessed on the worker 169 * thread. So we need to pass it in. 170 */ 171 class GetUserAgentRunnable final : public WorkerMainThreadRunnable { 172 nsString& mUA; 173 bool mShouldResistFingerprinting; 174 175 public: 176 GetUserAgentRunnable(WorkerPrivate* aWorkerPrivate, nsString& aUA, 177 bool aShouldResistFingerprinting) 178 : WorkerMainThreadRunnable(aWorkerPrivate, "UserAgent getter"_ns), 179 mUA(aUA), 180 mShouldResistFingerprinting(aShouldResistFingerprinting) { 181 MOZ_ASSERT(aWorkerPrivate); 182 aWorkerPrivate->AssertIsOnWorkerThread(); 183 } 184 185 virtual bool MainThreadRun() override { 186 AssertIsOnMainThread(); 187 MOZ_ASSERT(mWorkerRef); 188 189 WorkerPrivate* workerPrivate = mWorkerRef->Private(); 190 191 nsCOMPtr<nsPIDOMWindowInner> window = workerPrivate->GetWindow(); 192 193 nsresult rv = 194 dom::Navigator::GetUserAgent(window, workerPrivate->GetDocument(), 195 Some(mShouldResistFingerprinting), mUA); 196 if (NS_FAILED(rv)) { 197 NS_WARNING("Failed to retrieve user-agent from the worker thread."); 198 } 199 200 return true; 201 } 202 }; 203 204 } // namespace 205 206 void WorkerNavigator::GetUserAgent(nsString& aUserAgent, CallerType aCallerType, 207 ErrorResult& aRv) const { 208 WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); 209 MOZ_ASSERT(workerPrivate); 210 211 RefPtr<GetUserAgentRunnable> runnable = new GetUserAgentRunnable( 212 workerPrivate, aUserAgent, 213 workerPrivate->ShouldResistFingerprinting(RFPTarget::NavigatorUserAgent)); 214 215 runnable->Dispatch(workerPrivate, Canceling, aRv); 216 } 217 218 uint64_t WorkerNavigator::HardwareConcurrency() const { 219 RuntimeService* rts = RuntimeService::GetService(); 220 MOZ_ASSERT(rts); 221 222 WorkerPrivate* aWorkerPrivate = GetCurrentThreadWorkerPrivate(); 223 224 return rts->ClampedHardwareConcurrency( 225 aWorkerPrivate->ShouldResistFingerprinting( 226 RFPTarget::NavigatorHWConcurrency), 227 aWorkerPrivate->ShouldResistFingerprinting( 228 RFPTarget::NavigatorHWConcurrencyTiered)); 229 } 230 231 StorageManager* WorkerNavigator::Storage() { 232 if (!mStorageManager) { 233 WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); 234 MOZ_ASSERT(workerPrivate); 235 236 RefPtr<nsIGlobalObject> global = workerPrivate->GlobalScope(); 237 MOZ_ASSERT(global); 238 239 mStorageManager = new StorageManager(global); 240 241 workerPrivate->NotifyStorageKeyUsed(); 242 } 243 244 return mStorageManager; 245 } 246 247 network::Connection* WorkerNavigator::GetConnection(ErrorResult& aRv) { 248 if (!mConnection) { 249 WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); 250 MOZ_ASSERT(workerPrivate); 251 252 mConnection = network::Connection::CreateForWorker(workerPrivate, aRv); 253 } 254 255 return mConnection; 256 } 257 258 dom::MediaCapabilities* WorkerNavigator::MediaCapabilities() { 259 if (!mMediaCapabilities) { 260 WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); 261 MOZ_ASSERT(workerPrivate); 262 263 nsIGlobalObject* global = workerPrivate->GlobalScope(); 264 MOZ_ASSERT(global); 265 266 mMediaCapabilities = new dom::MediaCapabilities(global); 267 } 268 return mMediaCapabilities; 269 } 270 271 webgpu::Instance* WorkerNavigator::Gpu() { 272 if (!mWebGpu) { 273 WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); 274 MOZ_ASSERT(workerPrivate); 275 276 nsIGlobalObject* global = workerPrivate->GlobalScope(); 277 MOZ_ASSERT(global); 278 279 mWebGpu = webgpu::Instance::Create(global); 280 } 281 return mWebGpu; 282 } 283 284 dom::LockManager* WorkerNavigator::Locks() { 285 if (!mLocks) { 286 WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); 287 MOZ_ASSERT(workerPrivate); 288 289 nsIGlobalObject* global = workerPrivate->GlobalScope(); 290 MOZ_ASSERT(global); 291 292 mLocks = dom::LockManager::Create(*global); 293 } 294 return mLocks; 295 } 296 297 dom::Permissions* WorkerNavigator::Permissions() { 298 if (!mPermissions) { 299 WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); 300 MOZ_ASSERT(workerPrivate); 301 302 nsIGlobalObject* global = workerPrivate->GlobalScope(); 303 MOZ_ASSERT(global); 304 mPermissions = new dom::Permissions(global); 305 } 306 307 return mPermissions; 308 } 309 310 already_AddRefed<ServiceWorkerContainer> WorkerNavigator::ServiceWorker() { 311 if (!mServiceWorkerContainer) { 312 WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); 313 MOZ_ASSERT(workerPrivate); 314 315 nsIGlobalObject* global = workerPrivate->GlobalScope(); 316 MOZ_ASSERT(global); 317 318 mServiceWorkerContainer = ServiceWorkerContainer::Create(global); 319 } 320 321 RefPtr<ServiceWorkerContainer> ref = mServiceWorkerContainer; 322 return ref.forget(); 323 } 324 325 } // namespace mozilla::dom