LCOV - code coverage report
Current view: top level - dom/workers - ServiceWorkerRegistrar.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 82 531 15.4 %
Date: 2017-07-14 16:53:18 Functions: 11 33 33.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : 
       2             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       3             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       4             : /* This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       7             : 
       8             : #include "ServiceWorkerRegistrar.h"
       9             : #include "mozilla/dom/ServiceWorkerRegistrarTypes.h"
      10             : 
      11             : #include "nsIEventTarget.h"
      12             : #include "nsIInputStream.h"
      13             : #include "nsILineInputStream.h"
      14             : #include "nsIObserverService.h"
      15             : #include "nsIOutputStream.h"
      16             : #include "nsISafeOutputStream.h"
      17             : 
      18             : #include "MainThreadUtils.h"
      19             : #include "mozilla/ClearOnShutdown.h"
      20             : #include "mozilla/ipc/BackgroundChild.h"
      21             : #include "mozilla/ipc/BackgroundParent.h"
      22             : #include "mozilla/ipc/PBackgroundChild.h"
      23             : #include "mozilla/ModuleUtils.h"
      24             : #include "mozilla/Services.h"
      25             : #include "mozilla/StaticPtr.h"
      26             : #include "nsAppDirectoryServiceDefs.h"
      27             : #include "nsContentUtils.h"
      28             : #include "nsDirectoryServiceUtils.h"
      29             : #include "nsNetCID.h"
      30             : #include "nsNetUtil.h"
      31             : #include "nsServiceManagerUtils.h"
      32             : #include "nsThreadUtils.h"
      33             : #include "nsXULAppAPI.h"
      34             : 
      35             : using namespace mozilla::ipc;
      36             : 
      37             : namespace mozilla {
      38             : namespace dom {
      39             : 
      40             : namespace {
      41             : 
      42             : static const char* gSupportedRegistrarVersions[] = {
      43             :   SERVICEWORKERREGISTRAR_VERSION,
      44             :   "6",
      45             :   "5",
      46             :   "4",
      47             :   "3",
      48             :   "2"
      49             : };
      50             : 
      51           3 : StaticRefPtr<ServiceWorkerRegistrar> gServiceWorkerRegistrar;
      52             : 
      53             : } // namespace
      54             : 
      55          21 : NS_IMPL_ISUPPORTS(ServiceWorkerRegistrar,
      56             :                   nsIObserver)
      57             : 
      58             : void
      59           3 : ServiceWorkerRegistrar::Initialize()
      60             : {
      61           3 :   MOZ_ASSERT(!gServiceWorkerRegistrar);
      62             : 
      63           3 :   if (!XRE_IsParentProcess()) {
      64           2 :     return;
      65             :   }
      66             : 
      67           1 :   gServiceWorkerRegistrar = new ServiceWorkerRegistrar();
      68           1 :   ClearOnShutdown(&gServiceWorkerRegistrar);
      69             : 
      70           2 :   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
      71           1 :   if (obs) {
      72           3 :     DebugOnly<nsresult> rv = obs->AddObserver(gServiceWorkerRegistrar,
      73           3 :                                               "profile-after-change", false);
      74           1 :     MOZ_ASSERT(NS_SUCCEEDED(rv));
      75             : 
      76           3 :     rv = obs->AddObserver(gServiceWorkerRegistrar, "profile-before-change",
      77           2 :                           false);
      78           1 :     MOZ_ASSERT(NS_SUCCEEDED(rv));
      79             :   }
      80             : }
      81             : 
      82             : /* static */ already_AddRefed<ServiceWorkerRegistrar>
      83           3 : ServiceWorkerRegistrar::Get()
      84             : {
      85           3 :   MOZ_ASSERT(XRE_IsParentProcess());
      86             : 
      87           3 :   MOZ_ASSERT(gServiceWorkerRegistrar);
      88           6 :   RefPtr<ServiceWorkerRegistrar> service = gServiceWorkerRegistrar.get();
      89           6 :   return service.forget();
      90             : }
      91             : 
      92           1 : ServiceWorkerRegistrar::ServiceWorkerRegistrar()
      93             :   : mMonitor("ServiceWorkerRegistrar.mMonitor")
      94             :   , mDataLoaded(false)
      95             :   , mShuttingDown(false)
      96             :   , mShutdownCompleteFlag(nullptr)
      97           1 :   , mRunnableCounter(0)
      98             : {
      99           1 :   MOZ_ASSERT(NS_IsMainThread());
     100           1 : }
     101             : 
     102           0 : ServiceWorkerRegistrar::~ServiceWorkerRegistrar()
     103             : {
     104           0 :   MOZ_ASSERT(!mRunnableCounter);
     105           0 : }
     106             : 
     107             : void
     108           3 : ServiceWorkerRegistrar::GetRegistrations(
     109             :                                nsTArray<ServiceWorkerRegistrationData>& aValues)
     110             : {
     111           3 :   MOZ_ASSERT(NS_IsMainThread());
     112           3 :   MOZ_ASSERT(aValues.IsEmpty());
     113             : 
     114           6 :   MonitorAutoLock lock(mMonitor);
     115             : 
     116             :   // If we don't have the profile directory, profile is not started yet (and
     117             :   // probably we are in a utest).
     118           3 :   if (!mProfileDir) {
     119           0 :     return;
     120             :   }
     121             : 
     122             :   // We care just about the first execution because this can be blocked by
     123             :   // loading data from disk.
     124             :   static bool firstTime = true;
     125           3 :   TimeStamp startTime;
     126             : 
     127           3 :   if (firstTime) {
     128           1 :     startTime = TimeStamp::NowLoRes();
     129             :   }
     130             : 
     131             :   // Waiting for data loaded.
     132           3 :   mMonitor.AssertCurrentThreadOwns();
     133           3 :   while (!mDataLoaded) {
     134           0 :     mMonitor.Wait();
     135             :   }
     136             : 
     137           3 :   aValues.AppendElements(mData);
     138             : 
     139           3 :   if (firstTime) {
     140           1 :     firstTime = false;
     141           1 :     Telemetry::AccumulateTimeDelta(
     142             :       Telemetry::SERVICE_WORKER_REGISTRATION_LOADING,
     143           1 :       startTime);
     144             :   }
     145             : }
     146             : 
     147             : namespace {
     148             : 
     149           0 : bool Equivalent(const ServiceWorkerRegistrationData& aLeft,
     150             :                 const ServiceWorkerRegistrationData& aRight)
     151             : {
     152           0 :   MOZ_ASSERT(aLeft.principal().type() ==
     153             :              mozilla::ipc::PrincipalInfo::TContentPrincipalInfo);
     154           0 :   MOZ_ASSERT(aRight.principal().type() ==
     155             :              mozilla::ipc::PrincipalInfo::TContentPrincipalInfo);
     156             : 
     157           0 :   const auto& leftPrincipal = aLeft.principal().get_ContentPrincipalInfo();
     158           0 :   const auto& rightPrincipal = aRight.principal().get_ContentPrincipalInfo();
     159             : 
     160             :   // Only compare the attributes, not the spec part of the principal.
     161             :   // The scope comparison above already covers the origin and codebase
     162             :   // principals include the full path in their spec which is not what
     163             :   // we want here.
     164           0 :   return aLeft.scope() == aRight.scope() &&
     165           0 :          leftPrincipal.attrs() == rightPrincipal.attrs();
     166             : }
     167             : 
     168             : } // anonymous namespace
     169             : 
     170             : void
     171           0 : ServiceWorkerRegistrar::RegisterServiceWorker(
     172             :                                      const ServiceWorkerRegistrationData& aData)
     173             : {
     174           0 :   AssertIsOnBackgroundThread();
     175             : 
     176           0 :   if (mShuttingDown) {
     177           0 :     NS_WARNING("Failed to register a serviceWorker during shutting down.");
     178           0 :     return;
     179             :   }
     180             : 
     181             :   {
     182           0 :     MonitorAutoLock lock(mMonitor);
     183           0 :     MOZ_ASSERT(mDataLoaded);
     184           0 :     RegisterServiceWorkerInternal(aData);
     185             :   }
     186             : 
     187           0 :   ScheduleSaveData();
     188             : }
     189             : 
     190             : void
     191           0 : ServiceWorkerRegistrar::UnregisterServiceWorker(
     192             :                                             const PrincipalInfo& aPrincipalInfo,
     193             :                                             const nsACString& aScope)
     194             : {
     195           0 :   AssertIsOnBackgroundThread();
     196             : 
     197           0 :   if (mShuttingDown) {
     198           0 :     NS_WARNING("Failed to unregister a serviceWorker during shutting down.");
     199           0 :     return;
     200             :   }
     201             : 
     202           0 :   bool deleted = false;
     203             : 
     204             :   {
     205           0 :     MonitorAutoLock lock(mMonitor);
     206           0 :     MOZ_ASSERT(mDataLoaded);
     207             : 
     208           0 :     ServiceWorkerRegistrationData tmp;
     209           0 :     tmp.principal() = aPrincipalInfo;
     210           0 :     tmp.scope() = aScope;
     211             : 
     212           0 :     for (uint32_t i = 0; i < mData.Length(); ++i) {
     213           0 :       if (Equivalent(tmp, mData[i])) {
     214           0 :         mData.RemoveElementAt(i);
     215           0 :         deleted = true;
     216           0 :         break;
     217             :       }
     218             :     }
     219             :   }
     220             : 
     221           0 :   if (deleted) {
     222           0 :     ScheduleSaveData();
     223             :   }
     224             : }
     225             : 
     226             : void
     227           0 : ServiceWorkerRegistrar::RemoveAll()
     228             : {
     229           0 :   AssertIsOnBackgroundThread();
     230             : 
     231           0 :   if (mShuttingDown) {
     232           0 :     NS_WARNING("Failed to remove all the serviceWorkers during shutting down.");
     233           0 :     return;
     234             :   }
     235             : 
     236           0 :   bool deleted = false;
     237             : 
     238             :   {
     239           0 :     MonitorAutoLock lock(mMonitor);
     240           0 :     MOZ_ASSERT(mDataLoaded);
     241             : 
     242           0 :     deleted = !mData.IsEmpty();
     243           0 :     mData.Clear();
     244             :   }
     245             : 
     246           0 :   if (deleted) {
     247           0 :     ScheduleSaveData();
     248             :   }
     249             : }
     250             : 
     251             : void
     252           1 : ServiceWorkerRegistrar::LoadData()
     253             : {
     254           1 :   MOZ_ASSERT(!NS_IsMainThread());
     255           1 :   MOZ_ASSERT(!mDataLoaded);
     256             : 
     257           1 :   nsresult rv = ReadData();
     258             : 
     259           1 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     260           0 :     DeleteData();
     261             :     // Also if the reading failed we have to notify what is waiting for data.
     262             :   }
     263             : 
     264           2 :   MonitorAutoLock lock(mMonitor);
     265           1 :   MOZ_ASSERT(!mDataLoaded);
     266           1 :   mDataLoaded = true;
     267           1 :   mMonitor.Notify();
     268           1 : }
     269             : 
     270             : nsresult
     271           1 : ServiceWorkerRegistrar::ReadData()
     272             : {
     273             :   // We cannot assert about the correct thread because normally this method
     274             :   // runs on a IO thread, but in gTests we call it from the main-thread.
     275             : 
     276           2 :   nsCOMPtr<nsIFile> file;
     277             : 
     278             :   {
     279           2 :     MonitorAutoLock lock(mMonitor);
     280             : 
     281           1 :     if (!mProfileDir) {
     282           0 :       return NS_ERROR_FAILURE;
     283             :     }
     284             : 
     285           1 :     nsresult rv = mProfileDir->Clone(getter_AddRefs(file));
     286           1 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     287           0 :       return rv;
     288             :     }
     289             :   }
     290             : 
     291           1 :   nsresult rv = file->Append(NS_LITERAL_STRING(SERVICEWORKERREGISTRAR_FILE));
     292           1 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     293           0 :     return rv;
     294             :   }
     295             : 
     296             :   bool exists;
     297           1 :   rv = file->Exists(&exists);
     298           1 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     299           0 :     return rv;
     300             :   }
     301             : 
     302           1 :   if (!exists) {
     303           1 :     return NS_OK;
     304             :   }
     305             : 
     306           0 :   nsCOMPtr<nsIInputStream> stream;
     307           0 :   rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), file);
     308           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     309           0 :     return rv;
     310             :   }
     311             : 
     312           0 :   nsCOMPtr<nsILineInputStream> lineInputStream = do_QueryInterface(stream);
     313           0 :   MOZ_ASSERT(lineInputStream);
     314             : 
     315           0 :   nsAutoCString version;
     316             :   bool hasMoreLines;
     317           0 :   rv = lineInputStream->ReadLine(version, &hasMoreLines);
     318           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     319           0 :     return rv;
     320             :   }
     321             : 
     322           0 :   if (!IsSupportedVersion(version)) {
     323           0 :     nsContentUtils::LogMessageToConsole(nsPrintfCString(
     324           0 :       "Unsupported service worker registrar version: %s", version.get()).get());
     325           0 :     return NS_ERROR_FAILURE;
     326             :   }
     327             : 
     328           0 :   nsTArray<ServiceWorkerRegistrationData> tmpData;
     329             : 
     330           0 :   bool overwrite = false;
     331           0 :   bool dedupe = false;
     332           0 :   while (hasMoreLines) {
     333           0 :     ServiceWorkerRegistrationData* entry = tmpData.AppendElement();
     334             : 
     335             : #define GET_LINE(x)                                   \
     336             :     rv = lineInputStream->ReadLine(x, &hasMoreLines); \
     337             :     if (NS_WARN_IF(NS_FAILED(rv))) {                  \
     338             :       return rv;                                      \
     339             :     }                                                 \
     340             :     if (NS_WARN_IF(!hasMoreLines)) {                  \
     341             :       return NS_ERROR_FAILURE;                        \
     342             :     }
     343             : 
     344           0 :     nsAutoCString line;
     345           0 :     nsAutoCString unused;
     346           0 :     if (version.EqualsLiteral(SERVICEWORKERREGISTRAR_VERSION)) {
     347           0 :       nsAutoCString suffix;
     348           0 :       GET_LINE(suffix);
     349             : 
     350           0 :       OriginAttributes attrs;
     351           0 :       if (!attrs.PopulateFromSuffix(suffix)) {
     352           0 :         return NS_ERROR_INVALID_ARG;
     353             :       }
     354             : 
     355           0 :       GET_LINE(entry->scope());
     356             : 
     357           0 :       entry->principal() =
     358           0 :         mozilla::ipc::ContentPrincipalInfo(attrs, void_t(), entry->scope());
     359             : 
     360           0 :       GET_LINE(entry->currentWorkerURL());
     361             : 
     362           0 :       nsAutoCString fetchFlag;
     363           0 :       GET_LINE(fetchFlag);
     364           0 :       if (!fetchFlag.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE) &&
     365           0 :           !fetchFlag.EqualsLiteral(SERVICEWORKERREGISTRAR_FALSE)) {
     366           0 :         return NS_ERROR_INVALID_ARG;
     367             :       }
     368           0 :       entry->currentWorkerHandlesFetch() =
     369           0 :         fetchFlag.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE);
     370             : 
     371           0 :       nsAutoCString cacheName;
     372           0 :       GET_LINE(cacheName);
     373           0 :       CopyUTF8toUTF16(cacheName, entry->cacheName());
     374             : 
     375           0 :       nsAutoCString loadFlags;
     376           0 :       GET_LINE(loadFlags);
     377           0 :       entry->loadFlags() = loadFlags.ToInteger(&rv, 16);
     378           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
     379           0 :         return rv;
     380           0 :       } else if (entry->loadFlags() != nsIRequest::LOAD_NORMAL &&
     381           0 :                  entry->loadFlags() != nsIRequest::VALIDATE_ALWAYS) {
     382           0 :         return NS_ERROR_INVALID_ARG;
     383             :       }
     384             : 
     385           0 :       nsAutoCString installedTimeStr;
     386           0 :       GET_LINE(installedTimeStr);
     387           0 :       int64_t installedTime = installedTimeStr.ToInteger64(&rv);
     388           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
     389           0 :         return rv;
     390             :       }
     391           0 :       entry->currentWorkerInstalledTime() = installedTime;
     392             : 
     393           0 :       nsAutoCString activatedTimeStr;
     394           0 :       GET_LINE(activatedTimeStr);
     395           0 :       int64_t activatedTime = activatedTimeStr.ToInteger64(&rv);
     396           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
     397           0 :         return rv;
     398             :       }
     399           0 :       entry->currentWorkerActivatedTime() = activatedTime;
     400             : 
     401           0 :       nsAutoCString lastUpdateTimeStr;
     402           0 :       GET_LINE(lastUpdateTimeStr);
     403           0 :       int64_t lastUpdateTime = lastUpdateTimeStr.ToInteger64(&rv);
     404           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
     405           0 :         return rv;
     406             :       }
     407           0 :       entry->lastUpdateTime() = lastUpdateTime;
     408           0 :     } else if (version.EqualsLiteral("6")) {
     409           0 :       nsAutoCString suffix;
     410           0 :       GET_LINE(suffix);
     411             : 
     412           0 :       OriginAttributes attrs;
     413           0 :       if (!attrs.PopulateFromSuffix(suffix)) {
     414           0 :         return NS_ERROR_INVALID_ARG;
     415             :       }
     416             : 
     417           0 :       GET_LINE(entry->scope());
     418             : 
     419           0 :       entry->principal() =
     420           0 :         mozilla::ipc::ContentPrincipalInfo(attrs, void_t(), entry->scope());
     421             : 
     422           0 :       GET_LINE(entry->currentWorkerURL());
     423             : 
     424           0 :       nsAutoCString fetchFlag;
     425           0 :       GET_LINE(fetchFlag);
     426           0 :       if (!fetchFlag.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE) &&
     427           0 :           !fetchFlag.EqualsLiteral(SERVICEWORKERREGISTRAR_FALSE)) {
     428           0 :         return NS_ERROR_INVALID_ARG;
     429             :       }
     430           0 :       entry->currentWorkerHandlesFetch() =
     431           0 :         fetchFlag.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE);
     432             : 
     433           0 :       nsAutoCString cacheName;
     434           0 :       GET_LINE(cacheName);
     435           0 :       CopyUTF8toUTF16(cacheName, entry->cacheName());
     436             : 
     437           0 :       nsAutoCString loadFlags;
     438           0 :       GET_LINE(loadFlags);
     439           0 :       entry->loadFlags() = loadFlags.ToInteger(&rv, 16);
     440           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
     441           0 :         return rv;
     442           0 :       } else if (entry->loadFlags() != nsIRequest::LOAD_NORMAL &&
     443           0 :                  entry->loadFlags() != nsIRequest::VALIDATE_ALWAYS) {
     444           0 :         return NS_ERROR_INVALID_ARG;
     445             :       }
     446             : 
     447           0 :       entry->currentWorkerInstalledTime() = 0;
     448           0 :       entry->currentWorkerActivatedTime() = 0;
     449           0 :       entry->lastUpdateTime() = 0;
     450           0 :     } else if (version.EqualsLiteral("5")) {
     451           0 :       overwrite = true;
     452           0 :       dedupe = true;
     453             : 
     454           0 :       nsAutoCString suffix;
     455           0 :       GET_LINE(suffix);
     456             : 
     457           0 :       OriginAttributes attrs;
     458           0 :       if (!attrs.PopulateFromSuffix(suffix)) {
     459           0 :         return NS_ERROR_INVALID_ARG;
     460             :       }
     461             : 
     462           0 :       GET_LINE(entry->scope());
     463             : 
     464           0 :       entry->principal() =
     465           0 :         mozilla::ipc::ContentPrincipalInfo(attrs, void_t(), entry->scope());
     466             : 
     467           0 :       GET_LINE(entry->currentWorkerURL());
     468             : 
     469           0 :       nsAutoCString fetchFlag;
     470           0 :       GET_LINE(fetchFlag);
     471           0 :       if (!fetchFlag.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE) &&
     472           0 :           !fetchFlag.EqualsLiteral(SERVICEWORKERREGISTRAR_FALSE)) {
     473           0 :         return NS_ERROR_INVALID_ARG;
     474             :       }
     475           0 :       entry->currentWorkerHandlesFetch() =
     476           0 :         fetchFlag.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE);
     477             : 
     478           0 :       nsAutoCString cacheName;
     479           0 :       GET_LINE(cacheName);
     480           0 :       CopyUTF8toUTF16(cacheName, entry->cacheName());
     481             : 
     482           0 :       entry->loadFlags() = nsIRequest::VALIDATE_ALWAYS;
     483             : 
     484           0 :       entry->currentWorkerInstalledTime() = 0;
     485           0 :       entry->currentWorkerActivatedTime() = 0;
     486           0 :       entry->lastUpdateTime() = 0;
     487           0 :     } else if (version.EqualsLiteral("4")) {
     488           0 :       overwrite = true;
     489           0 :       dedupe = true;
     490             : 
     491           0 :       nsAutoCString suffix;
     492           0 :       GET_LINE(suffix);
     493             : 
     494           0 :       OriginAttributes attrs;
     495           0 :       if (!attrs.PopulateFromSuffix(suffix)) {
     496           0 :         return NS_ERROR_INVALID_ARG;
     497             :       }
     498             : 
     499           0 :       GET_LINE(entry->scope());
     500             : 
     501           0 :       entry->principal() =
     502           0 :         mozilla::ipc::ContentPrincipalInfo(attrs, void_t(), entry->scope());
     503             : 
     504           0 :       GET_LINE(entry->currentWorkerURL());
     505             : 
     506             :       // default handlesFetch flag to Enabled
     507           0 :       entry->currentWorkerHandlesFetch() = true;
     508             : 
     509           0 :       nsAutoCString cacheName;
     510           0 :       GET_LINE(cacheName);
     511           0 :       CopyUTF8toUTF16(cacheName, entry->cacheName());
     512             : 
     513           0 :       entry->loadFlags() = nsIRequest::VALIDATE_ALWAYS;
     514             : 
     515           0 :       entry->currentWorkerInstalledTime() = 0;
     516           0 :       entry->currentWorkerActivatedTime() = 0;
     517           0 :       entry->lastUpdateTime() = 0;
     518           0 :     } else if (version.EqualsLiteral("3")) {
     519           0 :       overwrite = true;
     520           0 :       dedupe = true;
     521             : 
     522           0 :       nsAutoCString suffix;
     523           0 :       GET_LINE(suffix);
     524             : 
     525           0 :       OriginAttributes attrs;
     526           0 :       if (!attrs.PopulateFromSuffix(suffix)) {
     527           0 :         return NS_ERROR_INVALID_ARG;
     528             :       }
     529             : 
     530             :       // principal spec is no longer used; we use scope directly instead
     531           0 :       GET_LINE(unused);
     532             : 
     533           0 :       GET_LINE(entry->scope());
     534             : 
     535           0 :       entry->principal() =
     536           0 :         mozilla::ipc::ContentPrincipalInfo(attrs, void_t(), entry->scope());
     537             : 
     538           0 :       GET_LINE(entry->currentWorkerURL());
     539             : 
     540             :       // default handlesFetch flag to Enabled
     541           0 :       entry->currentWorkerHandlesFetch() = true;
     542             : 
     543           0 :       nsAutoCString cacheName;
     544           0 :       GET_LINE(cacheName);
     545           0 :       CopyUTF8toUTF16(cacheName, entry->cacheName());
     546             : 
     547           0 :       entry->loadFlags() = nsIRequest::VALIDATE_ALWAYS;
     548             : 
     549           0 :       entry->currentWorkerInstalledTime() = 0;
     550           0 :       entry->currentWorkerActivatedTime() = 0;
     551           0 :       entry->lastUpdateTime() = 0;
     552           0 :     } else if (version.EqualsLiteral("2")) {
     553           0 :       overwrite = true;
     554           0 :       dedupe = true;
     555             : 
     556           0 :       nsAutoCString suffix;
     557           0 :       GET_LINE(suffix);
     558             : 
     559           0 :       OriginAttributes attrs;
     560           0 :       if (!attrs.PopulateFromSuffix(suffix)) {
     561           0 :         return NS_ERROR_INVALID_ARG;
     562             :       }
     563             : 
     564             :       // principal spec is no longer used; we use scope directly instead
     565           0 :       GET_LINE(unused);
     566             : 
     567           0 :       GET_LINE(entry->scope());
     568             : 
     569           0 :       entry->principal() =
     570           0 :         mozilla::ipc::ContentPrincipalInfo(attrs, void_t(), entry->scope());
     571             : 
     572             :       // scriptSpec is no more used in latest version.
     573           0 :       GET_LINE(unused);
     574             : 
     575           0 :       GET_LINE(entry->currentWorkerURL());
     576             : 
     577             :       // default handlesFetch flag to Enabled
     578           0 :       entry->currentWorkerHandlesFetch() = true;
     579             : 
     580           0 :       nsAutoCString cacheName;
     581           0 :       GET_LINE(cacheName);
     582           0 :       CopyUTF8toUTF16(cacheName, entry->cacheName());
     583             : 
     584             :       // waitingCacheName is no more used in latest version.
     585           0 :       GET_LINE(unused);
     586             : 
     587           0 :       entry->loadFlags() = nsIRequest::VALIDATE_ALWAYS;
     588             : 
     589           0 :       entry->currentWorkerInstalledTime() = 0;
     590           0 :       entry->currentWorkerActivatedTime() = 0;
     591           0 :       entry->lastUpdateTime() = 0;
     592             :     } else {
     593           0 :       MOZ_ASSERT_UNREACHABLE("Should never get here!");
     594             :     }
     595             : 
     596             : #undef GET_LINE
     597             : 
     598           0 :     rv = lineInputStream->ReadLine(line, &hasMoreLines);
     599           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     600           0 :       return rv;
     601             :     }
     602             : 
     603           0 :     if (!line.EqualsLiteral(SERVICEWORKERREGISTRAR_TERMINATOR)) {
     604           0 :       return NS_ERROR_FAILURE;
     605             :     }
     606             :   }
     607             : 
     608           0 :   stream->Close();
     609             : 
     610             :   // Copy data over to mData.
     611           0 :   for (uint32_t i = 0; i < tmpData.Length(); ++i) {
     612           0 :     bool match = false;
     613           0 :     if (dedupe) {
     614           0 :       MOZ_ASSERT(overwrite);
     615             :       // If this is an old profile, then we might need to deduplicate.  In
     616             :       // theory this can be removed in the future (Bug 1248449)
     617           0 :       for (uint32_t j = 0; j < mData.Length(); ++j) {
     618             :         // Use same comparison as RegisterServiceWorker. Scope contains
     619             :         // basic origin information.  Combine with any principal attributes.
     620           0 :         if (Equivalent(tmpData[i], mData[j])) {
     621             :           // Last match wins, just like legacy loading used to do in
     622             :           // the ServiceWorkerManager.
     623           0 :           mData[j] = tmpData[i];
     624             :           // Dupe found, so overwrite file with reduced list.
     625           0 :           match = true;
     626           0 :           break;
     627             :         }
     628             :       }
     629             :     } else {
     630             : #ifdef DEBUG
     631             :       // Otherwise assert no duplications in debug builds.
     632           0 :       for (uint32_t j = 0; j < mData.Length(); ++j) {
     633           0 :         MOZ_ASSERT(!Equivalent(tmpData[i], mData[j]));
     634             :       }
     635             : #endif
     636             :     }
     637           0 :     if (!match) {
     638           0 :       mData.AppendElement(tmpData[i]);
     639             :     }
     640             :   }
     641             : 
     642             :   // Overwrite previous version.
     643             :   // Cannot call SaveData directly because gtest uses main-thread.
     644           0 :   if (overwrite && NS_FAILED(WriteData())) {
     645           0 :     NS_WARNING("Failed to write data for the ServiceWorker Registations.");
     646           0 :     DeleteData();
     647             :   }
     648             : 
     649           0 :   return NS_OK;
     650             : }
     651             : 
     652             : void
     653           0 : ServiceWorkerRegistrar::DeleteData()
     654             : {
     655             :   // We cannot assert about the correct thread because normally this method
     656             :   // runs on a IO thread, but in gTests we call it from the main-thread.
     657             : 
     658           0 :   nsCOMPtr<nsIFile> file;
     659             : 
     660             :   {
     661           0 :     MonitorAutoLock lock(mMonitor);
     662           0 :     mData.Clear();
     663             : 
     664           0 :     if (!mProfileDir) {
     665           0 :       return;
     666             :     }
     667             : 
     668           0 :     nsresult rv = mProfileDir->Clone(getter_AddRefs(file));
     669           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     670           0 :       return;
     671             :     }
     672             :   }
     673             : 
     674           0 :   nsresult rv = file->Append(NS_LITERAL_STRING(SERVICEWORKERREGISTRAR_FILE));
     675           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     676           0 :     return;
     677             :   }
     678             : 
     679           0 :   rv = file->Remove(false);
     680           0 :   if (rv == NS_ERROR_FILE_NOT_FOUND) {
     681           0 :     return;
     682             :   }
     683             : 
     684           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     685           0 :     return;
     686             :   }
     687             : }
     688             : 
     689             : void
     690           0 : ServiceWorkerRegistrar::RegisterServiceWorkerInternal(const ServiceWorkerRegistrationData& aData)
     691             : {
     692           0 :   bool found = false;
     693           0 :   for (uint32_t i = 0, len = mData.Length(); i < len; ++i) {
     694           0 :     if (Equivalent(aData, mData[i])) {
     695           0 :       mData[i] = aData;
     696           0 :       found = true;
     697           0 :       break;
     698             :     }
     699             :   }
     700             : 
     701           0 :   if (!found) {
     702           0 :     mData.AppendElement(aData);
     703             :   }
     704           0 : }
     705             : 
     706           0 : class ServiceWorkerRegistrarSaveDataRunnable final : public Runnable
     707             : {
     708             : public:
     709           0 :   ServiceWorkerRegistrarSaveDataRunnable()
     710           0 :     : Runnable("dom::ServiceWorkerRegistrarSaveDataRunnable")
     711           0 :     , mEventTarget(GetCurrentThreadEventTarget())
     712             :   {
     713           0 :     AssertIsOnBackgroundThread();
     714           0 :   }
     715             : 
     716             :   NS_IMETHOD
     717           0 :   Run() override
     718             :   {
     719           0 :     RefPtr<ServiceWorkerRegistrar> service = ServiceWorkerRegistrar::Get();
     720           0 :     MOZ_ASSERT(service);
     721             : 
     722           0 :     service->SaveData();
     723             : 
     724             :     RefPtr<Runnable> runnable =
     725           0 :       NewRunnableMethod("ServiceWorkerRegistrar::DataSaved",
     726           0 :                         service, &ServiceWorkerRegistrar::DataSaved);
     727           0 :     nsresult rv = mEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL);
     728           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     729           0 :       return rv;
     730             :     }
     731             : 
     732           0 :     return NS_OK;
     733             :   }
     734             : 
     735             : private:
     736             :   nsCOMPtr<nsIEventTarget> mEventTarget;
     737             : };
     738             : 
     739             : void
     740           0 : ServiceWorkerRegistrar::ScheduleSaveData()
     741             : {
     742           0 :   AssertIsOnBackgroundThread();
     743           0 :   MOZ_ASSERT(!mShuttingDown);
     744             : 
     745             :   nsCOMPtr<nsIEventTarget> target =
     746           0 :     do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
     747           0 :   MOZ_ASSERT(target, "Must have stream transport service");
     748             : 
     749             :   RefPtr<Runnable> runnable =
     750           0 :     new ServiceWorkerRegistrarSaveDataRunnable();
     751           0 :   nsresult rv = target->Dispatch(runnable, NS_DISPATCH_NORMAL);
     752           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     753           0 :     return;
     754             :   }
     755             : 
     756           0 :   ++mRunnableCounter;
     757             : }
     758             : 
     759             : void
     760           0 : ServiceWorkerRegistrar::ShutdownCompleted()
     761             : {
     762           0 :   MOZ_ASSERT(NS_IsMainThread());
     763             : 
     764           0 :   MOZ_ASSERT(mShutdownCompleteFlag && !*mShutdownCompleteFlag);
     765           0 :   *mShutdownCompleteFlag = true;
     766           0 : }
     767             : 
     768             : void
     769           0 : ServiceWorkerRegistrar::SaveData()
     770             : {
     771           0 :   MOZ_ASSERT(!NS_IsMainThread());
     772             : 
     773           0 :   nsresult rv = WriteData();
     774           0 :   if (NS_FAILED(rv)) {
     775           0 :     NS_WARNING("Failed to write data for the ServiceWorker Registations.");
     776           0 :     DeleteData();
     777             :   }
     778           0 : }
     779             : 
     780             : void
     781           0 : ServiceWorkerRegistrar::DataSaved()
     782             : {
     783           0 :   AssertIsOnBackgroundThread();
     784           0 :   MOZ_ASSERT(mRunnableCounter);
     785             : 
     786           0 :   --mRunnableCounter;
     787           0 :   MaybeScheduleShutdownCompleted();
     788           0 : }
     789             : 
     790             : void
     791           0 : ServiceWorkerRegistrar::MaybeScheduleShutdownCompleted()
     792             : {
     793           0 :   AssertIsOnBackgroundThread();
     794             : 
     795           0 :   if (mRunnableCounter || !mShuttingDown) {
     796           0 :     return;
     797             :   }
     798             : 
     799             :   RefPtr<Runnable> runnable =
     800           0 :     NewRunnableMethod("dom::ServiceWorkerRegistrar::ShutdownCompleted",
     801             :                       this,
     802           0 :                       &ServiceWorkerRegistrar::ShutdownCompleted);
     803           0 :   nsresult rv = NS_DispatchToMainThread(runnable);
     804           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     805           0 :     return;
     806             :   }
     807             : }
     808             : 
     809             : bool
     810           0 : ServiceWorkerRegistrar::IsSupportedVersion(const nsACString& aVersion) const
     811             : {
     812           0 :   uint32_t numVersions = ArrayLength(gSupportedRegistrarVersions);
     813           0 :   for (uint32_t i = 0; i < numVersions; i++) {
     814           0 :     if (aVersion.EqualsASCII(gSupportedRegistrarVersions[i])) {
     815           0 :       return true;
     816             :     }
     817             :   }
     818           0 :   return false;
     819             : }
     820             : 
     821             : nsresult
     822           0 : ServiceWorkerRegistrar::WriteData()
     823             : {
     824             :   // We cannot assert about the correct thread because normally this method
     825             :   // runs on a IO thread, but in gTests we call it from the main-thread.
     826             : 
     827           0 :   nsCOMPtr<nsIFile> file;
     828             : 
     829             :   {
     830           0 :     MonitorAutoLock lock(mMonitor);
     831             : 
     832           0 :     if (!mProfileDir) {
     833           0 :       return NS_ERROR_FAILURE;
     834             :     }
     835             : 
     836           0 :     nsresult rv = mProfileDir->Clone(getter_AddRefs(file));
     837           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     838           0 :       return rv;
     839             :     }
     840             :   }
     841             : 
     842           0 :   nsresult rv = file->Append(NS_LITERAL_STRING(SERVICEWORKERREGISTRAR_FILE));
     843           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     844           0 :     return rv;
     845             :   }
     846             : 
     847             :   // We need a lock to take a snapshot of the data.
     848           0 :   nsTArray<ServiceWorkerRegistrationData> data;
     849             :   {
     850           0 :     MonitorAutoLock lock(mMonitor);
     851           0 :     data = mData;
     852             :   }
     853             : 
     854           0 :   nsCOMPtr<nsIOutputStream> stream;
     855           0 :   rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(stream), file);
     856           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     857           0 :     return rv;
     858             :   }
     859             : 
     860           0 :   nsAutoCString buffer;
     861           0 :   buffer.AppendLiteral(SERVICEWORKERREGISTRAR_VERSION);
     862           0 :   buffer.Append('\n');
     863             : 
     864             :   uint32_t count;
     865           0 :   rv = stream->Write(buffer.Data(), buffer.Length(), &count);
     866           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     867           0 :     return rv;
     868             :   }
     869             : 
     870           0 :   if (count != buffer.Length()) {
     871           0 :     return NS_ERROR_UNEXPECTED;
     872             :   }
     873             : 
     874           0 :   for (uint32_t i = 0, len = data.Length(); i < len; ++i) {
     875           0 :     const mozilla::ipc::PrincipalInfo& info = data[i].principal();
     876             : 
     877           0 :     MOZ_ASSERT(info.type() == mozilla::ipc::PrincipalInfo::TContentPrincipalInfo);
     878             : 
     879             :     const mozilla::ipc::ContentPrincipalInfo& cInfo =
     880           0 :       info.get_ContentPrincipalInfo();
     881             : 
     882           0 :     nsAutoCString suffix;
     883           0 :     cInfo.attrs().CreateSuffix(suffix);
     884             : 
     885           0 :     buffer.Truncate();
     886           0 :     buffer.Append(suffix.get());
     887           0 :     buffer.Append('\n');
     888             : 
     889           0 :     buffer.Append(data[i].scope());
     890           0 :     buffer.Append('\n');
     891             : 
     892           0 :     buffer.Append(data[i].currentWorkerURL());
     893           0 :     buffer.Append('\n');
     894             : 
     895           0 :     buffer.Append(data[i].currentWorkerHandlesFetch() ?
     896           0 :                     SERVICEWORKERREGISTRAR_TRUE : SERVICEWORKERREGISTRAR_FALSE);
     897           0 :     buffer.Append('\n');
     898             : 
     899           0 :     buffer.Append(NS_ConvertUTF16toUTF8(data[i].cacheName()));
     900           0 :     buffer.Append('\n');
     901             : 
     902           0 :     buffer.AppendInt(data[i].loadFlags(), 16);
     903           0 :     buffer.Append('\n');
     904           0 :     MOZ_DIAGNOSTIC_ASSERT(data[i].loadFlags() == nsIRequest::LOAD_NORMAL ||
     905             :                           data[i].loadFlags() == nsIRequest::VALIDATE_ALWAYS);
     906             : 
     907             :     static_assert(nsIRequest::LOAD_NORMAL == 0,
     908             :                   "LOAD_NORMAL matches serialized value.");
     909             :     static_assert(nsIRequest::VALIDATE_ALWAYS == (1 << 11),
     910             :                   "VALIDATE_ALWAYS matches serialized value");
     911             : 
     912           0 :     buffer.AppendInt(data[i].currentWorkerInstalledTime());
     913           0 :     buffer.Append('\n');
     914             : 
     915           0 :     buffer.AppendInt(data[i].currentWorkerActivatedTime());
     916           0 :     buffer.Append('\n');
     917             : 
     918           0 :     buffer.AppendInt(data[i].lastUpdateTime());
     919           0 :     buffer.Append('\n');
     920             : 
     921           0 :     buffer.AppendLiteral(SERVICEWORKERREGISTRAR_TERMINATOR);
     922           0 :     buffer.Append('\n');
     923             : 
     924           0 :     rv = stream->Write(buffer.Data(), buffer.Length(), &count);
     925           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     926           0 :       return rv;
     927             :     }
     928             : 
     929           0 :     if (count != buffer.Length()) {
     930           0 :       return NS_ERROR_UNEXPECTED;
     931             :     }
     932             :   }
     933             : 
     934           0 :   nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(stream);
     935           0 :   MOZ_ASSERT(safeStream);
     936             : 
     937           0 :   rv = safeStream->Finish();
     938           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     939           0 :     return rv;
     940             :   }
     941             : 
     942           0 :   return NS_OK;
     943             : }
     944             : 
     945             : void
     946           1 : ServiceWorkerRegistrar::ProfileStarted()
     947             : {
     948           1 :   MOZ_ASSERT(NS_IsMainThread());
     949             : 
     950           2 :   MonitorAutoLock lock(mMonitor);
     951           1 :   MOZ_DIAGNOSTIC_ASSERT(!mProfileDir);
     952             : 
     953           1 :   nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
     954           2 :                                        getter_AddRefs(mProfileDir));
     955           1 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     956           0 :     return;
     957             :   }
     958             : 
     959             :   nsCOMPtr<nsIEventTarget> target =
     960           2 :     do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
     961           1 :   MOZ_ASSERT(target, "Must have stream transport service");
     962             : 
     963             :   nsCOMPtr<nsIRunnable> runnable =
     964           2 :     NewRunnableMethod("dom::ServiceWorkerRegistrar::LoadData",
     965             :                       this,
     966           2 :                       &ServiceWorkerRegistrar::LoadData);
     967           1 :   rv = target->Dispatch(runnable, NS_DISPATCH_NORMAL);
     968           1 :   if (NS_FAILED(rv)) {
     969           0 :     NS_WARNING("Failed to dispatch the LoadDataRunnable.");
     970             :   }
     971             : }
     972             : 
     973             : void
     974           0 : ServiceWorkerRegistrar::ProfileStopped()
     975             : {
     976           0 :   MOZ_ASSERT(NS_IsMainThread());
     977             : 
     978           0 :   MonitorAutoLock lock(mMonitor);
     979             : 
     980           0 :   if (!mProfileDir) {
     981           0 :     nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
     982           0 :                                          getter_AddRefs(mProfileDir));
     983           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     984           0 :       return;
     985             :     }
     986             :   }
     987             : 
     988           0 :   PBackgroundChild* child = BackgroundChild::GetForCurrentThread();
     989           0 :   if (!child) {
     990           0 :     return;
     991             :   }
     992             : 
     993           0 :   bool completed = false;
     994           0 :   mShutdownCompleteFlag = &completed;
     995             : 
     996           0 :   child->SendShutdownServiceWorkerRegistrar();
     997             : 
     998           0 :   MOZ_ALWAYS_TRUE(SpinEventLoopUntil([&]() { return completed; }));
     999             : }
    1000             : 
    1001             : void
    1002           0 : ServiceWorkerRegistrar::Shutdown()
    1003             : {
    1004           0 :   AssertIsOnBackgroundThread();
    1005           0 :   MOZ_ASSERT(!mShuttingDown);
    1006             : 
    1007           0 :   mShuttingDown = true;
    1008           0 :   MaybeScheduleShutdownCompleted();
    1009           0 : }
    1010             : 
    1011             : NS_IMETHODIMP
    1012           1 : ServiceWorkerRegistrar::Observe(nsISupports* aSubject, const char* aTopic,
    1013             :                                 const char16_t* aData)
    1014             : {
    1015           1 :   MOZ_ASSERT(NS_IsMainThread());
    1016             : 
    1017           1 :   if (!strcmp(aTopic, "profile-after-change")) {
    1018             :     nsCOMPtr<nsIObserverService> observerService =
    1019           2 :       services::GetObserverService();
    1020           1 :     observerService->RemoveObserver(this, "profile-after-change");
    1021             : 
    1022             :     // The profile is fully loaded, now we can proceed with the loading of data
    1023             :     // from disk.
    1024           1 :     ProfileStarted();
    1025             : 
    1026           1 :     return NS_OK;
    1027             :   }
    1028             : 
    1029           0 :   if (!strcmp(aTopic, "profile-before-change")) {
    1030             :     nsCOMPtr<nsIObserverService> observerService =
    1031           0 :       services::GetObserverService();
    1032           0 :     observerService->RemoveObserver(this, "profile-before-change");
    1033             : 
    1034             :     // Shutting down, let's sync the data.
    1035           0 :     ProfileStopped();
    1036             : 
    1037           0 :     return NS_OK;
    1038             :   }
    1039             : 
    1040           0 :   MOZ_ASSERT(false, "ServiceWorkerRegistrar got unexpected topic!");
    1041             :   return NS_ERROR_UNEXPECTED;
    1042             : }
    1043             : 
    1044             : } // namespace dom
    1045             : } // namespace mozilla

Generated by: LCOV version 1.13