Пример #1
0
void
ServiceWorkerUpdateJob::Install(ServiceWorkerManager* aSWM)
{
  AssertIsOnMainThread();
  MOZ_DIAGNOSTIC_ASSERT(!Canceled());
  MOZ_DIAGNOSTIC_ASSERT(aSWM);

  MOZ_ASSERT(!mRegistration->GetInstalling());

  // Begin step 2 of the Install algorithm.
  //
  //  https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#installation-algorithm

  mRegistration->TransitionEvaluatingToInstalling();

  // Step 6 of the Install algorithm resolving the job promise.
  InvokeResultCallbacks(NS_OK);

  // The job promise cannot be rejected after this point, but the job can
  // still fail; e.g. if the install event handler throws, etc.

  // fire the updatefound event
  nsCOMPtr<nsIRunnable> upr =
    NewRunnableMethod<RefPtr<ServiceWorkerRegistrationInfo>>(
      "dom::workers::ServiceWorkerManager::"
      "FireUpdateFoundOnServiceWorkerRegistrations",
      aSWM,
      &ServiceWorkerManager::FireUpdateFoundOnServiceWorkerRegistrations,
      mRegistration);
  NS_DispatchToMainThread(upr);

  // Call ContinueAfterInstallEvent(false) on main thread if the SW
  // script fails to load.
  nsCOMPtr<nsIRunnable> failRunnable = NewRunnableMethod<bool>(
    "dom::workers::ServiceWorkerUpdateJob::ContinueAfterInstallEvent",
    this,
    &ServiceWorkerUpdateJob::ContinueAfterInstallEvent,
    false);

  nsMainThreadPtrHandle<ServiceWorkerUpdateJob> handle(
    new nsMainThreadPtrHolder<ServiceWorkerUpdateJob>(
      "ServiceWorkerUpdateJob", this));
  RefPtr<LifeCycleEventCallback> callback = new ContinueInstallRunnable(handle);

  // Send the install event to the worker thread
  ServiceWorkerPrivate* workerPrivate =
    mRegistration->GetInstalling()->WorkerPrivate();
  nsresult rv = workerPrivate->SendLifeCycleEvent(NS_LITERAL_STRING("install"),
                                                  callback, failRunnable);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    ContinueAfterInstallEvent(false /* aSuccess */);
  }
}
void
ServiceWorkerRegistrationInfo::Activate()
{
  if (!mWaitingWorker) {
    return;
  }

  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
  if (!swm) {
    // browser shutdown began during async activation step
    return;
  }

  TransitionWaitingToActive();

  // FIXME(nsm): Unlink appcache if there is one.

  swm->CheckPendingReadyPromises();

  // "Queue a task to fire a simple event named controllerchange..."
  nsCOMPtr<nsIRunnable> controllerChangeRunnable =
    NewRunnableMethod<RefPtr<ServiceWorkerRegistrationInfo>>(
      swm, &ServiceWorkerManager::FireControllerChange, this);
  NS_DispatchToMainThread(controllerChangeRunnable);

  nsCOMPtr<nsIRunnable> failRunnable =
    NewRunnableMethod<bool>(this,
                            &ServiceWorkerRegistrationInfo::FinishActivate,
                            false /* success */);

  nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> handle(
    new nsMainThreadPtrHolder<ServiceWorkerRegistrationInfo>(this));
  RefPtr<LifeCycleEventCallback> callback = new ContinueActivateRunnable(handle);

  ServiceWorkerPrivate* workerPrivate = mActiveWorker->WorkerPrivate();
  MOZ_ASSERT(workerPrivate);
  nsresult rv = workerPrivate->SendLifeCycleEvent(NS_LITERAL_STRING("activate"),
                                                  callback, failRunnable);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(failRunnable));
    return;
  }
}
Пример #3
0
void
ServiceWorkerUpdateJob::ComparisonResult(nsresult aStatus,
                                         bool aInCacheAndEqual,
                                         const nsAString& aNewCacheName,
                                         const nsACString& aMaxScope,
                                         nsLoadFlags aLoadFlags)
{
  AssertIsOnMainThread();

  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
  if (NS_WARN_IF(Canceled() || !swm)) {
    FailUpdateJob(NS_ERROR_DOM_ABORT_ERR);
    return;
  }

  // Handle failure of the download or comparison.  This is part of Update
  // step 5 as "If the algorithm asynchronously completes with null, then:".
  if (NS_WARN_IF(NS_FAILED(aStatus))) {
    FailUpdateJob(aStatus);
    return;
  }

  // The spec validates the response before performing the byte-for-byte check.
  // Here we perform the comparison in another module and then validate the
  // script URL and scope.  Make sure to do this validation before accepting
  // an byte-for-byte match since the service-worker-allowed header might have
  // changed since the last time it was installed.

  // This is step 2 the "validate response" section of Update algorithm step 5.
  // Step 1 is performed in the serviceWorkerScriptCache code.

  nsCOMPtr<nsIURI> scriptURI;
  nsresult rv = NS_NewURI(getter_AddRefs(scriptURI), mScriptSpec);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    FailUpdateJob(NS_ERROR_DOM_SECURITY_ERR);
    return;
  }

  nsCOMPtr<nsIURI> maxScopeURI;
  if (!aMaxScope.IsEmpty()) {
    rv = NS_NewURI(getter_AddRefs(maxScopeURI), aMaxScope,
                   nullptr, scriptURI);
    if (NS_WARN_IF(NS_FAILED(rv))) {
      FailUpdateJob(NS_ERROR_DOM_SECURITY_ERR);
      return;
    }
  }

  mLoadFlags = aLoadFlags;

  nsAutoCString defaultAllowedPrefix;
  rv = GetRequiredScopeStringPrefix(scriptURI, defaultAllowedPrefix,
                                    eUseDirectory);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    FailUpdateJob(NS_ERROR_DOM_SECURITY_ERR);
    return;
  }

  nsAutoCString maxPrefix(defaultAllowedPrefix);
  if (maxScopeURI) {
    rv = GetRequiredScopeStringPrefix(maxScopeURI, maxPrefix, eUsePath);
    if (NS_WARN_IF(NS_FAILED(rv))) {
      FailUpdateJob(NS_ERROR_DOM_SECURITY_ERR);
      return;
    }
  }

  if (!StringBeginsWith(mRegistration->mScope, maxPrefix)) {
    nsAutoString message;
    NS_ConvertUTF8toUTF16 reportScope(mRegistration->mScope);
    NS_ConvertUTF8toUTF16 reportMaxPrefix(maxPrefix);
    const char16_t* params[] = { reportScope.get(), reportMaxPrefix.get() };

    rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
                                               "ServiceWorkerScopePathMismatch",
                                               params, message);
    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to format localized string");
    swm->ReportToAllClients(mScope,
                            message,
                            EmptyString(),
                            EmptyString(), 0, 0,
                            nsIScriptError::errorFlag);
    FailUpdateJob(NS_ERROR_DOM_SECURITY_ERR);
    return;
  }

  // The response has been validated, so now we can consider if its a
  // byte-for-byte match.  This is step 6 of the Update algorithm.
  if (aInCacheAndEqual) {
    Finish(NS_OK);
    return;
  }

  Telemetry::Accumulate(Telemetry::SERVICE_WORKER_UPDATED, 1);

  // Begin step 7 of the Update algorithm to evaluate the new script.

  RefPtr<ServiceWorkerInfo> sw =
    new ServiceWorkerInfo(mRegistration->mPrincipal,
                          mRegistration->mScope,
                          mScriptSpec,
                          aNewCacheName,
                          mLoadFlags);

  mRegistration->SetEvaluating(sw);

  nsMainThreadPtrHandle<ServiceWorkerUpdateJob> handle(
      new nsMainThreadPtrHolder<ServiceWorkerUpdateJob>(
        "ServiceWorkerUpdateJob", this));
  RefPtr<LifeCycleEventCallback> callback = new ContinueUpdateRunnable(handle);

  ServiceWorkerPrivate* workerPrivate = sw->WorkerPrivate();
  MOZ_ASSERT(workerPrivate);
  rv = workerPrivate->CheckScriptEvaluation(callback);

  if (NS_WARN_IF(NS_FAILED(rv))) {
    FailUpdateJob(NS_ERROR_DOM_ABORT_ERR);
    return;
  }
}