SharedWorkerService.cpp (10282B)
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 "SharedWorkerService.h" 8 9 #include "mozilla/BasePrincipal.h" 10 #include "mozilla/ClearOnShutdown.h" 11 #include "mozilla/SchedulerGroup.h" 12 #include "mozilla/StaticMutex.h" 13 #include "mozilla/dom/MessagePort.h" 14 #include "mozilla/dom/RemoteWorkerManager.h" // RemoteWorkerManager::GetRemoteType 15 #include "mozilla/dom/RemoteWorkerTypes.h" 16 #include "mozilla/dom/SharedWorkerManager.h" 17 #include "mozilla/ipc/BackgroundParent.h" 18 #include "mozilla/ipc/URIUtils.h" 19 #include "nsIPrincipal.h" 20 #include "nsProxyRelease.h" 21 22 namespace mozilla { 23 24 using namespace ipc; 25 26 namespace dom { 27 28 namespace { 29 30 StaticMutex sSharedWorkerMutex; 31 32 StaticRefPtr<SharedWorkerService> sSharedWorkerService; 33 34 class GetOrCreateWorkerManagerRunnable final : public Runnable { 35 public: 36 GetOrCreateWorkerManagerRunnable(SharedWorkerService* aService, 37 SharedWorkerParent* aActor, 38 const RemoteWorkerData& aData, 39 uint64_t aWindowID, 40 const MessagePortIdentifier& aPortIdentifier) 41 : Runnable("GetOrCreateWorkerManagerRunnable"), 42 mBackgroundEventTarget(GetCurrentSerialEventTarget()), 43 mService(aService), 44 mActor(aActor), 45 mData(aData), 46 mWindowID(aWindowID), 47 mPortIdentifier(aPortIdentifier) {} 48 49 NS_IMETHOD 50 Run() { 51 mService->GetOrCreateWorkerManagerOnMainThread( 52 mBackgroundEventTarget, mActor, mData, mWindowID, mPortIdentifier); 53 54 return NS_OK; 55 } 56 57 private: 58 nsCOMPtr<nsIEventTarget> mBackgroundEventTarget; 59 RefPtr<SharedWorkerService> mService; 60 RefPtr<SharedWorkerParent> mActor; 61 RemoteWorkerData mData; 62 uint64_t mWindowID; 63 UniqueMessagePortId mPortIdentifier; 64 }; 65 66 class WorkerManagerCreatedRunnable final : public Runnable { 67 public: 68 WorkerManagerCreatedRunnable( 69 already_AddRefed<SharedWorkerManagerWrapper> aManagerWrapper, 70 SharedWorkerParent* aActor, const RemoteWorkerData& aData, 71 uint64_t aWindowID, UniqueMessagePortId& aPortIdentifier) 72 : Runnable("WorkerManagerCreatedRunnable"), 73 mManagerWrapper(aManagerWrapper), 74 mActor(aActor), 75 mData(aData), 76 mWindowID(aWindowID), 77 mPortIdentifier(std::move(aPortIdentifier)) {} 78 79 NS_IMETHOD 80 Run() { 81 AssertIsOnBackgroundThread(); 82 83 if (NS_WARN_IF( 84 !mActor->CanSend() || 85 !mManagerWrapper->Manager()->MaybeCreateRemoteWorker( 86 mData, mWindowID, mPortIdentifier, mActor->OtherPid()))) { 87 // If we cannot send, the error won't arrive, but we may log something. 88 mActor->ErrorPropagation(NS_ERROR_FAILURE); 89 return NS_OK; 90 } 91 92 mManagerWrapper->Manager()->AddActor(mActor); 93 mActor->ManagerCreated(mManagerWrapper.forget()); 94 return NS_OK; 95 } 96 97 private: 98 RefPtr<SharedWorkerManagerWrapper> mManagerWrapper; 99 RefPtr<SharedWorkerParent> mActor; 100 RemoteWorkerData mData; 101 uint64_t mWindowID; 102 UniqueMessagePortId mPortIdentifier; 103 }; 104 105 class ErrorPropagationRunnable final : public Runnable { 106 public: 107 ErrorPropagationRunnable(SharedWorkerParent* aActor, nsresult aError) 108 : Runnable("ErrorPropagationRunnable"), mActor(aActor), mError(aError) {} 109 110 NS_IMETHOD 111 Run() { 112 AssertIsOnBackgroundThread(); 113 mActor->ErrorPropagation(mError); 114 return NS_OK; 115 } 116 117 private: 118 RefPtr<SharedWorkerParent> mActor; 119 nsresult mError; 120 }; 121 122 } // namespace 123 124 /* static */ 125 already_AddRefed<SharedWorkerService> SharedWorkerService::GetOrCreate() { 126 AssertIsOnBackgroundThread(); 127 128 StaticMutexAutoLock lock(sSharedWorkerMutex); 129 130 if (!sSharedWorkerService) { 131 sSharedWorkerService = new SharedWorkerService(); 132 // ClearOnShutdown can only be called on main thread 133 nsresult rv = SchedulerGroup::Dispatch(NS_NewRunnableFunction( 134 "RegisterSharedWorkerServiceClearOnShutdown", []() { 135 StaticMutexAutoLock lock(sSharedWorkerMutex); 136 MOZ_ASSERT(sSharedWorkerService); 137 ClearOnShutdown(&sSharedWorkerService); 138 })); 139 (void)NS_WARN_IF(NS_FAILED(rv)); 140 } 141 142 RefPtr<SharedWorkerService> instance = sSharedWorkerService; 143 return instance.forget(); 144 } 145 146 /* static */ 147 SharedWorkerService* SharedWorkerService::Get() { 148 StaticMutexAutoLock lock(sSharedWorkerMutex); 149 150 MOZ_ASSERT(sSharedWorkerService); 151 return sSharedWorkerService; 152 } 153 154 void SharedWorkerService::GetOrCreateWorkerManager( 155 SharedWorkerParent* aActor, const RemoteWorkerData& aData, 156 uint64_t aWindowID, const MessagePortIdentifier& aPortIdentifier) { 157 AssertIsOnBackgroundThread(); 158 159 // The real check happens on main-thread. 160 RefPtr<GetOrCreateWorkerManagerRunnable> r = 161 new GetOrCreateWorkerManagerRunnable(this, aActor, aData, aWindowID, 162 aPortIdentifier); 163 164 nsresult rv = SchedulerGroup::Dispatch(r.forget()); 165 (void)NS_WARN_IF(NS_FAILED(rv)); 166 } 167 168 void SharedWorkerService::GetOrCreateWorkerManagerOnMainThread( 169 nsIEventTarget* aBackgroundEventTarget, SharedWorkerParent* aActor, 170 const RemoteWorkerData& aData, uint64_t aWindowID, 171 UniqueMessagePortId& aPortIdentifier) { 172 MOZ_ASSERT(NS_IsMainThread()); 173 MOZ_ASSERT(aBackgroundEventTarget); 174 MOZ_ASSERT(aActor); 175 176 RemoteWorkerData copyData = aData; 177 auto principalOrErr = PrincipalInfoToPrincipal(copyData.principalInfo()); 178 if (NS_WARN_IF(principalOrErr.isErr())) { 179 ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor, 180 principalOrErr.unwrapErr()); 181 return; 182 } 183 184 nsCOMPtr<nsIPrincipal> principal = principalOrErr.unwrap(); 185 auto remoteType = RemoteWorkerManager::GetRemoteType( 186 principal, WorkerKind::WorkerKindShared); 187 if (NS_WARN_IF(remoteType.isErr())) { 188 ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor, 189 remoteType.unwrapErr()); 190 return; 191 } 192 193 if (!remoteType.unwrap().Equals(copyData.remoteType())) { 194 copyData.remoteType() = remoteType.unwrap(); 195 } 196 197 auto partitionedPrincipalOrErr = 198 PrincipalInfoToPrincipal(copyData.partitionedPrincipalInfo()); 199 if (NS_WARN_IF(partitionedPrincipalOrErr.isErr())) { 200 ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor, 201 partitionedPrincipalOrErr.unwrapErr()); 202 return; 203 } 204 205 auto loadingPrincipalOrErr = 206 PrincipalInfoToPrincipal(copyData.loadingPrincipalInfo()); 207 if (NS_WARN_IF(loadingPrincipalOrErr.isErr())) { 208 ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor, 209 loadingPrincipalOrErr.unwrapErr()); 210 return; 211 } 212 213 RefPtr<SharedWorkerManagerHolder> managerHolder; 214 215 nsCOMPtr<nsIPrincipal> loadingPrincipal = loadingPrincipalOrErr.unwrap(); 216 nsCOMPtr<nsIPrincipal> partitionedPrincipal = 217 partitionedPrincipalOrErr.unwrap(); 218 219 nsCOMPtr<nsIPrincipal> effectiveStoragePrincipal = partitionedPrincipal; 220 if (copyData.useRegularPrincipal()) { 221 effectiveStoragePrincipal = loadingPrincipal; 222 } 223 224 // Let's see if there is already a SharedWorker to share. 225 nsCOMPtr<nsIURI> resolvedScriptURL = 226 DeserializeURI(copyData.resolvedScriptURL()); 227 for (SharedWorkerManager* workerManager : mWorkerManagers) { 228 bool matchNameButNotOptions = false; 229 230 managerHolder = workerManager->MatchOnMainThread( 231 this, copyData, resolvedScriptURL, loadingPrincipal, 232 BasePrincipal::Cast(effectiveStoragePrincipal)->OriginAttributesRef(), 233 &matchNameButNotOptions); 234 if (managerHolder) { 235 break; 236 } 237 238 if (matchNameButNotOptions) { 239 MismatchOptionsErrorPropagationOnMainThread(aBackgroundEventTarget, 240 aActor); 241 return; 242 } 243 } 244 245 // Let's create a new one. 246 if (!managerHolder) { 247 managerHolder = SharedWorkerManager::Create( 248 this, aBackgroundEventTarget, copyData, loadingPrincipal, 249 BasePrincipal::Cast(effectiveStoragePrincipal)->OriginAttributesRef()); 250 251 mWorkerManagers.AppendElement(managerHolder->Manager()); 252 } else { 253 // We are attaching the actor to an existing one. 254 if (managerHolder->Manager()->IsSecureContext() != 255 copyData.isSecureContext()) { 256 ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor, 257 NS_ERROR_DOM_SECURITY_ERR); 258 return; 259 } 260 } 261 262 RefPtr<SharedWorkerManagerWrapper> wrapper = 263 new SharedWorkerManagerWrapper(managerHolder.forget()); 264 265 RefPtr<WorkerManagerCreatedRunnable> r = new WorkerManagerCreatedRunnable( 266 wrapper.forget(), aActor, copyData, aWindowID, aPortIdentifier); 267 aBackgroundEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL); 268 } 269 270 void SharedWorkerService::ErrorPropagationOnMainThread( 271 nsIEventTarget* aBackgroundEventTarget, SharedWorkerParent* aActor, 272 nsresult aError) { 273 MOZ_ASSERT(NS_IsMainThread()); 274 MOZ_ASSERT(aBackgroundEventTarget); 275 MOZ_ASSERT(aActor); 276 MOZ_ASSERT(NS_FAILED(aError)); 277 278 RefPtr<ErrorPropagationRunnable> r = 279 new ErrorPropagationRunnable(aActor, aError); 280 aBackgroundEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL); 281 } 282 283 void SharedWorkerService::MismatchOptionsErrorPropagationOnMainThread( 284 nsIEventTarget* aBackgroundEventTarget, SharedWorkerParent* aActor) { 285 MOZ_ASSERT(NS_IsMainThread()); 286 MOZ_ASSERT(aBackgroundEventTarget); 287 MOZ_ASSERT(aActor); 288 289 aBackgroundEventTarget->Dispatch( 290 NS_NewRunnableFunction(__func__, 291 [aActor = RefPtr(aActor)] { 292 AssertIsOnBackgroundThread(); 293 aActor->MismatchOptionsErrorPropagation(); 294 }), 295 NS_DISPATCH_NORMAL); 296 } 297 298 void SharedWorkerService::RemoveWorkerManagerOnMainThread( 299 SharedWorkerManager* aManager) { 300 MOZ_ASSERT(NS_IsMainThread()); 301 MOZ_ASSERT(aManager); 302 MOZ_ASSERT(mWorkerManagers.Contains(aManager)); 303 304 mWorkerManagers.RemoveElement(aManager); 305 } 306 307 } // namespace dom 308 } // namespace mozilla