Bug 1293277 P6 Use the ClientInfo.Id() value for FetchEvent.clientId. r=baku
authorBen Kelly <ben@wanderview.com>
Tue, 12 Dec 2017 15:44:48 -0500
changeset 434815 baa02d97591ea55e6b9ee1867061c3e9e0324021
parent 434814 63938d2d5492022b7d3808d11a87faf83742ed6b
child 434816 3a2388a414a4792d0f0bf598df9f8d0b2b391ee6
push idunknown
push userunknown
push dateunknown
reviewersbaku
bugs1293277
milestone59.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1293277 P6 Use the ClientInfo.Id() value for FetchEvent.clientId. r=baku
docshell/base/nsDocShell.cpp
docshell/base/nsDocShell.h
dom/base/nsDocument.cpp
dom/base/nsDocument.h
dom/base/nsIDocument.h
dom/interfaces/base/nsIServiceWorkerManager.idl
dom/workers/ServiceWorkerManager.cpp
dom/workers/ServiceWorkerManager.h
dom/workers/ServiceWorkerPrivate.cpp
dom/workers/ServiceWorkerPrivate.h
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -15274,28 +15274,23 @@ nsDocShell::ChannelIntercepted(nsIInterc
   nsCOMPtr<nsIDocument> doc;
 
   bool isSubresourceLoad = !nsContentUtils::IsNonSubresourceRequest(channel);
   if (isSubresourceLoad) {
     doc = GetDocument();
     if (!doc) {
       return NS_ERROR_NOT_AVAILABLE;
     }
-  } else {
-    // For top-level navigations, save a document ID which will be passed to
-    // the FetchEvent as the clientId later on.
-    rv = nsIDocument::GenerateDocumentId(mInterceptedDocumentId);
-    NS_ENSURE_SUCCESS(rv, rv);
   }
 
   bool isReload = mLoadType & LOAD_CMD_RELOAD;
 
   ErrorResult error;
-  swm->DispatchFetchEvent(mOriginAttributes, doc, mInterceptedDocumentId,
-                          aChannel, isReload, isSubresourceLoad, error);
+  swm->DispatchFetchEvent(mOriginAttributes, doc, aChannel, isReload,
+                          isSubresourceLoad, error);
   if (NS_WARN_IF(error.Failed())) {
     return error.StealNSResult();
   }
 
   return NS_OK;
 }
 
 bool
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -369,21 +369,16 @@ public:
   const mozilla::OriginAttributes&
   GetOriginAttributes()
   {
     return mOriginAttributes;
   }
 
   nsresult SetOriginAttributes(const mozilla::OriginAttributes& aAttrs);
 
-  void GetInterceptedDocumentId(nsAString& aId)
-  {
-    aId = mInterceptedDocumentId;
-  }
-
 private:
   // An observed docshell wrapper is created when recording markers is enabled.
   mozilla::UniquePtr<mozilla::ObservedDocShell> mObserved;
 
   // It is necessary to allow adding a timeline marker wherever a docshell
   // instance is available. This operation happens frequently and needs to
   // be very fast, so instead of using a Map or having to search for some
   // docshell-specific markers storage, a pointer to an `ObservedDocShell` is
@@ -1146,18 +1141,16 @@ protected:
 
   // This represents the state of private browsing in the docshell.
   // Currently treated as a binary value: 1 - in private mode, 0 - not private mode
   // On content docshells mPrivateBrowsingId == mOriginAttributes.mPrivateBrowsingId
   // On chrome docshells this value will be set, but not have the corresponding
   // origin attribute set.
   uint32_t mPrivateBrowsingId;
 
-  nsString mInterceptedDocumentId;
-
   // This represents the CSS display-mode we are currently using.
   // It can be any of the following values from nsIDocShell.idl:
   //
   // DISPLAY_MODE_BROWSER = 0
   // DISPLAY_MODE_MINIMAL_UI = 1
   // DISPLAY_MODE_STANDALONE = 2
   // DISPLAY_MODE_FULLSCREEN = 3
   //
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1859,17 +1859,16 @@ NS_INTERFACE_TABLE_HEAD(nsDocument)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMDocumentXBL)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIScriptObjectPrincipal)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMEventTarget)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, mozilla::dom::EventTarget)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsISupportsWeakReference)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIRadioGroupContainer)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIMutationObserver)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIApplicationCacheContainer)
-    NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIObserver)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMXPathEvaluator)
   NS_INTERFACE_TABLE_END
   NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsDocument)
 NS_INTERFACE_MAP_END
 
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDocument)
 NS_IMETHODIMP_(MozExternalRefCountType)
@@ -5131,38 +5130,16 @@ nsDocument::SetScriptGlobalObject(nsIScr
         // of bfcache.  Clear our state to allow that to happen.  Only
         // clear this flag if we are actually controlled, though, so pages
         // that were force reloaded don't become controlled when they
         // come out of bfcache.
         mMaybeServiceWorkerControlled = false;
       }
       swm->MaybeStopControlling(this);
     }
-
-    // Remove ourself from the list of clients.  We only register
-    // content principal documents in this list.
-    if (!nsContentUtils::IsSystemPrincipal(GetPrincipal()) &&
-        !GetPrincipal()->GetIsNullPrincipal()) {
-      nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
-      if (os) {
-        os->RemoveObserver(this, "service-worker-get-client");
-      }
-    }
-
-  } else if (!mScriptGlobalObject && aScriptGlobalObject &&
-             mDocumentContainer && GetChannel() &&
-             !nsContentUtils::IsSystemPrincipal(GetPrincipal()) &&
-             !GetPrincipal()->GetIsNullPrincipal()) {
-    // This document is being activated.  Register it in the list of
-    // clients.  We only do this for content principal documents
-    // since we can never observe system or null principals.
-    nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
-    if (os) {
-      os->AddObserver(this, "service-worker-get-client", /* ownsWeak */ false);
-    }
   }
 
   // BlockOnload() might be called before mScriptGlobalObject is set.
   // We may need to add the blocker once mScriptGlobalObject is set.
   bool needOnloadBlocker = !mScriptGlobalObject && aScriptGlobalObject;
 
   mScriptGlobalObject = aScriptGlobalObject;
 
@@ -5273,25 +5250,17 @@ nsDocument::SetScriptGlobalObject(nsIScr
     // If we are shift-reloaded, don't associate with a ServiceWorker.
     if (IsForceReloadType(loadType)) {
       NS_WARNING("Page was shift reloaded, skipping ServiceWorker control");
       return;
     }
 
     nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
     if (swm) {
-      // If this document is being resurrected from the bfcache, then we may
-      // already have a document ID.  In that case reuse the same ID.  Otherwise
-      // get our document ID from the docshell.
-      nsString documentId(GetId());
-      if (documentId.IsEmpty()) {
-        static_cast<nsDocShell*>(docShell.get())->GetInterceptedDocumentId(documentId);
-      }
-
-      swm->MaybeStartControlling(this, documentId);
+      swm->MaybeStartControlling(this);
       mMaybeServiceWorkerControlled = true;
     }
   }
 }
 
 nsIScriptGlobalObject*
 nsDocument::GetScriptHandlingObjectInternal() const
 {
@@ -12437,42 +12406,16 @@ nsIDocument::GetPointerLockElement()
     do_QueryReferent(EventStateManager::sPointerLockedDoc);
   if (pointerLockedDoc != this) {
     return nullptr;
   }
 
   return pointerLockedElement;
 }
 
-nsresult
-nsDocument::Observe(nsISupports *aSubject,
-                    const char *aTopic,
-                    const char16_t *aData)
-{
-  if (strcmp("service-worker-get-client", aTopic) == 0) {
-    // No need to generate the ID if it doesn't exist here.  The ID being
-    // requested must already be generated in order to passed in as
-    // aSubject.
-    nsString clientId = GetId();
-    if (!clientId.IsEmpty() && clientId.Equals(aData)) {
-      nsCOMPtr<nsISupportsInterfacePointer> ifptr = do_QueryInterface(aSubject);
-      if (ifptr) {
-#ifdef DEBUG
-        nsCOMPtr<nsISupports> value;
-        MOZ_ALWAYS_SUCCEEDS(ifptr->GetData(getter_AddRefs(value)));
-        MOZ_ASSERT(!value);
-#endif
-        ifptr->SetData(static_cast<nsIDocument*>(this));
-        ifptr->SetDataIID(&NS_GET_IID(nsIDocument));
-      }
-    }
-  }
-  return NS_OK;
-}
-
 void
 nsDocument::UpdateVisibilityState()
 {
   dom::VisibilityState oldState = mVisibilityState;
   mVisibilityState = GetVisibilityState();
   if (oldState != mVisibilityState) {
     nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument*>(this),
                                          NS_LITERAL_STRING("visibilitychange"),
@@ -13192,59 +13135,16 @@ nsIDocument::CreateHTMLElement(nsAtom* a
   DebugOnly<nsresult> rv = NS_NewHTMLElement(getter_AddRefs(element),
                                              nodeInfo.forget(),
                                              mozilla::dom::NOT_FROM_PARSER);
 
   MOZ_ASSERT(NS_SUCCEEDED(rv), "NS_NewHTMLElement should never fail");
   return element.forget();
 }
 
-/* static */
-nsresult
-nsIDocument::GenerateDocumentId(nsAString& aId)
-{
-  nsID id;
-  nsresult rv = nsContentUtils::GenerateUUIDInPlace(id);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  // Build a string in {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} format
-  char buffer[NSID_LENGTH];
-  id.ToProvidedString(buffer);
-  NS_ConvertASCIItoUTF16 uuid(buffer);
-
-  // Remove {} and the null terminator
-  aId.Assign(Substring(uuid, 1, NSID_LENGTH - 3));
-  return NS_OK;
-}
-
-nsresult
-nsIDocument::GetOrCreateId(nsAString& aId)
-{
-  if (mId.IsEmpty()) {
-    nsresult rv = GenerateDocumentId(mId);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-  }
-
-  aId = mId;
-  return NS_OK;
-}
-
-void
-nsIDocument::SetId(const nsAString& aId)
-{
-  // The ID should only be set one time, but we may get the same value
-  // more than once if the document is controlled coming out of bfcache.
-  MOZ_ASSERT_IF(mId != aId, mId.IsEmpty());
-  mId = aId;
-}
-
 bool
 MarkDocumentTreeToBeInSyncOperation(nsIDocument* aDoc, void* aData)
 {
   nsCOMArray<nsIDocument>* documents =
     static_cast<nsCOMArray<nsIDocument>*>(aData);
   if (aDoc) {
     aDoc->SetIsInSyncOperation(true);
     if (nsCOMPtr<nsPIDOMWindowInner> window = aDoc->GetInnerWindow()) {
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -354,17 +354,16 @@ class PrincipalFlashClassifier;
 class nsDocument : public nsIDocument,
                    public nsIDOMDocument,
                    public nsIDOMDocumentXBL,
                    public nsSupportsWeakReference,
                    public nsIScriptObjectPrincipal,
                    public nsIRadioGroupContainer,
                    public nsIApplicationCacheContainer,
                    public nsStubMutationObserver,
-                   public nsIObserver,
                    public nsIDOMXPathEvaluator
 {
   friend class nsIDocument;
 
 public:
   typedef mozilla::dom::Element Element;
   using nsIDocument::GetElementsByTagName;
   typedef mozilla::net::ReferrerPolicy ReferrerPolicy;
@@ -693,19 +692,16 @@ public:
     GetExistingListenerManager() const override;
 
   // nsIScriptObjectPrincipal
   virtual nsIPrincipal* GetPrincipal() override;
 
   // nsIApplicationCacheContainer
   NS_DECL_NSIAPPLICATIONCACHECONTAINER
 
-  // nsIObserver
-  NS_DECL_NSIOBSERVER
-
   NS_DECL_NSIDOMXPATHEVALUATOR
 
   virtual nsresult Init();
 
   virtual already_AddRefed<Element> CreateElem(const nsAString& aName,
                                                nsAtom* aPrefix,
                                                int32_t aNamespaceID,
                                                const nsAString* aIs = nullptr) override;
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -1082,20 +1082,16 @@ public:
    * inserted anonymous content (in other words, the clone of the aElement
    * that was passed to InsertAnonymousContent).
    */
   Element* GetAnonRootIfInAnonymousContentContainer(nsINode* aNode) const;
   nsTArray<RefPtr<mozilla::dom::AnonymousContent>>& GetAnonymousContents() {
     return mAnonymousContents;
   }
 
-  static nsresult GenerateDocumentId(nsAString& aId);
-  nsresult GetOrCreateId(nsAString& aId);
-  void SetId(const nsAString& aId);
-
   mozilla::TimeStamp GetPageUnloadingEventTimeStamp() const
   {
     if (!mParentDocument) {
       return mPageUnloadingEventTimeStamp;
     }
 
     mozilla::TimeStamp parentTimeStamp(mParentDocument->GetPageUnloadingEventTimeStamp());
     if (parentTimeStamp.IsNull()) {
@@ -3328,21 +3324,16 @@ protected:
 
   mozilla::dom::XPathEvaluator* XPathEvaluator();
 
   void HandleRebuildUserFontSet() {
     mPostedFlushUserFontSet = false;
     FlushUserFontSet();
   }
 
-  const nsString& GetId() const
-  {
-    return mId;
-  }
-
   // Update our frame request callback scheduling state, if needed.  This will
   // schedule or unschedule them, if necessary, and update
   // mFrameRequestCallbacksScheduled.  aOldShell should only be passed when
   // mPresShell is becoming null; in that case it will be used to get hold of
   // the relevant refresh driver.
   void UpdateFrameRequestCallbackSchedulingState(nsIPresShell* aOldShell = nullptr);
 
   // Helper for GetScrollingElement/IsScrollingElement.
@@ -3691,17 +3682,16 @@ protected:
   uint32_t mSandboxFlags;
 
   nsCString mContentLanguage;
 
   // The channel that got passed to nsDocument::StartDocumentLoad(), if any.
   nsCOMPtr<nsIChannel> mChannel;
 private:
   nsCString mContentType;
-  nsString mId;
 protected:
 
   // The document's security info
   nsCOMPtr<nsISupports> mSecurityInfo;
 
   // The channel that failed to load and resulted in an error page.
   // This only applies to error pages. Might be null.
   nsCOMPtr<nsIChannel> mFailedChannel;
--- a/dom/interfaces/base/nsIServiceWorkerManager.idl
+++ b/dom/interfaces/base/nsIServiceWorkerManager.idl
@@ -143,17 +143,17 @@ interface nsIServiceWorkerManager : nsIS
                                                               in DOMString aScope);
 
   /**
    * Call this to request that document `aDoc` be controlled by a ServiceWorker
    * if a registration exists for it's scope.
    *
    * This MUST only be called once per document!
    */
-  [notxpcom,nostdcall] void MaybeStartControlling(in nsIDocument aDoc, in DOMString aDocumentId);
+  [notxpcom,nostdcall] void MaybeStartControlling(in nsIDocument aDoc);
 
   /**
    * Documents that have called MaybeStartControlling() should call this when
    * they are destroyed. This function may be called multiple times, and is
    * idempotent.
    */
   [notxpcom,nostdcall] void MaybeStopControlling(in nsIDocument aDoc);
 
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -2296,26 +2296,25 @@ ServiceWorkerManager::MaybeRemoveRegistr
     if (entry.Data()->mOrderedScopes.IsEmpty() &&
         entry.Data()->mJobQueues.Count() == 0) {
       entry.Remove();
     }
   }
 }
 
 void
-ServiceWorkerManager::MaybeStartControlling(nsIDocument* aDoc,
-                                            const nsAString& aDocumentId)
+ServiceWorkerManager::MaybeStartControlling(nsIDocument* aDoc)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aDoc);
   RefPtr<ServiceWorkerRegistrationInfo> registration =
     GetServiceWorkerRegistrationInfo(aDoc);
   if (registration) {
     MOZ_ASSERT(!mControlledDocuments.Contains(aDoc));
-    StartControllingADocument(registration, aDoc, aDocumentId);
+    StartControllingADocument(registration, aDoc);
   }
 }
 
 void
 ServiceWorkerManager::MaybeStopControlling(nsIDocument* aDoc)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aDoc);
@@ -2347,34 +2346,30 @@ ServiceWorkerManager::MaybeCheckNavigati
   mControlledDocuments.Get(aDoc, getter_AddRefs(registration));
   if (registration) {
     registration->MaybeScheduleUpdate();
   }
 }
 
 RefPtr<GenericPromise>
 ServiceWorkerManager::StartControllingADocument(ServiceWorkerRegistrationInfo* aRegistration,
-                                                nsIDocument* aDoc,
-                                                const nsAString& aDocumentId)
+                                                nsIDocument* aDoc)
 {
   MOZ_ASSERT(aRegistration);
   MOZ_ASSERT(aDoc);
 
 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
   auto storageAllowed = nsContentUtils::StorageAllowedForDocument(aDoc);
   MOZ_DIAGNOSTIC_ASSERT(storageAllowed == nsContentUtils::StorageAccess::eAllow);
 #endif // MOZ_DIAGNOSTIC_ASSERT_ENABLED
 
   RefPtr<GenericPromise> ref = GenericPromise::CreateAndResolve(true, __func__);
 
   aRegistration->StartControllingADocument();
   mControlledDocuments.Put(aDoc, aRegistration);
-  if (!aDocumentId.IsEmpty()) {
-    aDoc->SetId(aDocumentId);
-  }
 
   // Mark the document's ClientSource as controlled using the ClientHandle
   // interface.  While we could get at the ClientSource directly from the
   // document here, our goal is to move ServiceWorkerManager to a separate
   // process.  Using the ClientHandle supports this remote operation.
   ServiceWorkerInfo* activeWorker = aRegistration->GetActive();
   nsPIDOMWindowInner* innerWindow = aDoc->GetInnerWindow();
   if (activeWorker && innerWindow) {
@@ -2558,30 +2553,27 @@ ServiceWorkerManager::GetServiceWorkerFo
 
 namespace {
 
 class ContinueDispatchFetchEventRunnable : public Runnable
 {
   RefPtr<ServiceWorkerPrivate> mServiceWorkerPrivate;
   nsCOMPtr<nsIInterceptedChannel> mChannel;
   nsCOMPtr<nsILoadGroup> mLoadGroup;
-  nsString mDocumentId;
   bool mIsReload;
 public:
   ContinueDispatchFetchEventRunnable(
     ServiceWorkerPrivate* aServiceWorkerPrivate,
     nsIInterceptedChannel* aChannel,
     nsILoadGroup* aLoadGroup,
-    const nsAString& aDocumentId,
     bool aIsReload)
     : Runnable("dom::workers::ContinueDispatchFetchEventRunnable")
     , mServiceWorkerPrivate(aServiceWorkerPrivate)
     , mChannel(aChannel)
     , mLoadGroup(aLoadGroup)
-    , mDocumentId(aDocumentId)
     , mIsReload(aIsReload)
   {
     MOZ_ASSERT(aServiceWorkerPrivate);
     MOZ_ASSERT(aChannel);
   }
 
   void
   HandleError()
@@ -2612,70 +2604,72 @@ public:
     // if that happens.
     nsresult status;
     rv = channel->GetStatus(&status);
     if (NS_WARN_IF(NS_FAILED(rv) || NS_FAILED(status))) {
       HandleError();
       return NS_OK;
     }
 
-    rv = mServiceWorkerPrivate->SendFetchEvent(mChannel, mLoadGroup,
-                                               mDocumentId, mIsReload);
+    nsString clientId;
+    nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
+    if (loadInfo) {
+      Maybe<ClientInfo> clientInfo = loadInfo->GetClientInfo();
+      if (clientInfo.isSome()) {
+        char buf[NSID_LENGTH];
+        clientInfo.ref().Id().ToProvidedString(buf);
+        CopyUTF8toUTF16(nsDependentCString(buf), clientId);
+      }
+    }
+
+    rv = mServiceWorkerPrivate->SendFetchEvent(mChannel, mLoadGroup, clientId,
+                                               mIsReload);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       HandleError();
     }
 
     return NS_OK;
   }
 };
 
 } // anonymous namespace
 
 void
 ServiceWorkerManager::DispatchFetchEvent(const OriginAttributes& aOriginAttributes,
                                          nsIDocument* aDoc,
-                                         const nsAString& aDocumentIdForTopLevelNavigation,
                                          nsIInterceptedChannel* aChannel,
                                          bool aIsReload,
                                          bool aIsSubresourceLoad,
                                          ErrorResult& aRv)
 {
   MOZ_ASSERT(aChannel);
   AssertIsOnMainThread();
 
   RefPtr<ServiceWorkerInfo> serviceWorker;
   nsCOMPtr<nsILoadGroup> loadGroup;
-  nsAutoString documentId;
 
   if (aIsSubresourceLoad) {
     MOZ_ASSERT(aDoc);
 
     serviceWorker = GetActiveWorkerInfoForDocument(aDoc);
     if (!serviceWorker) {
       aRv.Throw(NS_ERROR_FAILURE);
       return;
     }
 
     loadGroup = aDoc->GetDocumentLoadGroup();
-    nsresult rv = aDoc->GetOrCreateId(documentId);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return;
-    }
   } else {
     nsCOMPtr<nsIChannel> internalChannel;
     aRv = aChannel->GetChannel(getter_AddRefs(internalChannel));
     if (NS_WARN_IF(aRv.Failed())) {
       return;
     }
 
     internalChannel->GetLoadGroup(getter_AddRefs(loadGroup));
 
-    // TODO: Use aDocumentIdForTopLevelNavigation for potentialClientId, pending
-    // the spec change.
-
     nsCOMPtr<nsIURI> uri;
     aRv = aChannel->GetSecureUpgradedChannelURI(getter_AddRefs(uri));
     if (NS_WARN_IF(aRv.Failed())) {
       return;
     }
 
     // non-subresource request means the URI contains the principal
     nsCOMPtr<nsIPrincipal> principal =
@@ -2745,18 +2739,17 @@ ServiceWorkerManager::DispatchFetchEvent
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
   MOZ_DIAGNOSTIC_ASSERT(serviceWorker);
 
   nsCOMPtr<nsIRunnable> continueRunnable =
     new ContinueDispatchFetchEventRunnable(serviceWorker->WorkerPrivate(),
-                                           aChannel, loadGroup,
-                                           documentId, aIsReload);
+                                           aChannel, loadGroup, aIsReload);
 
   // When this service worker was registered, we also sent down the permissions
   // for the runnable. They should have arrived by now, but we still need to
   // wait for them if they have not.
   nsCOMPtr<nsIRunnable> permissionsRunnable = NS_NewRunnableFunction(
     "dom::workers::ServiceWorkerManager::DispatchFetchEvent", [=]() {
       nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
       MOZ_ALWAYS_SUCCEEDS(permMgr->WhenPermissionsAvailable(serviceWorker->Principal(),
@@ -3219,17 +3212,17 @@ ServiceWorkerManager::MaybeClaimClient(n
         aWorkerRegistration == controllingRegistration) {
     return;
   }
 
   if (controllingRegistration) {
     StopControllingADocument(controllingRegistration);
   }
 
-  StartControllingADocument(aWorkerRegistration, aDocument, NS_LITERAL_STRING(""));
+  StartControllingADocument(aWorkerRegistration, aDocument);
   FireControllerChangeOnDocument(aDocument);
 }
 
 void
 ServiceWorkerManager::SetSkipWaitingFlag(nsIPrincipal* aPrincipal,
                                          const nsCString& aScope,
                                          uint64_t aServiceWorkerID)
 {
--- a/dom/workers/ServiceWorkerManager.h
+++ b/dom/workers/ServiceWorkerManager.h
@@ -145,17 +145,16 @@ public:
   // reasons without having to worry about shutdown races with the worker.
   bool
   MayHaveActiveServiceWorkerInstance(ContentParent* aContent,
                                      nsIPrincipal* aPrincipal);
 
   void
   DispatchFetchEvent(const OriginAttributes& aOriginAttributes,
                      nsIDocument* aDoc,
-                     const nsAString& aDocumentIdForTopLevelNavigation,
                      nsIInterceptedChannel* aChannel,
                      bool aIsReload,
                      bool aIsSubresourceLoad,
                      ErrorResult& aRv);
 
   void
   Update(nsIPrincipal* aPrincipal,
          const nsACString& aScope,
@@ -372,18 +371,17 @@ private:
   InvalidateServiceWorkerRegistrationWorker(ServiceWorkerRegistrationInfo* aRegistration,
                                             WhichServiceWorker aWhichOnes);
 
   void
   NotifyServiceWorkerRegistrationRemoved(ServiceWorkerRegistrationInfo* aRegistration);
 
   RefPtr<GenericPromise>
   StartControllingADocument(ServiceWorkerRegistrationInfo* aRegistration,
-                            nsIDocument* aDoc,
-                            const nsAString& aDocumentId);
+                            nsIDocument* aDoc);
 
   void
   StopControllingADocument(ServiceWorkerRegistrationInfo* aRegistration);
 
   already_AddRefed<ServiceWorkerRegistrationInfo>
   GetServiceWorkerRegistrationInfo(nsPIDOMWindowInner* aWindow);
 
   already_AddRefed<ServiceWorkerRegistrationInfo>
--- a/dom/workers/ServiceWorkerPrivate.cpp
+++ b/dom/workers/ServiceWorkerPrivate.cpp
@@ -1341,24 +1341,24 @@ class FetchEventRunnable : public Extend
 public:
   FetchEventRunnable(WorkerPrivate* aWorkerPrivate,
                      KeepAliveToken* aKeepAliveToken,
                      nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
                      // CSP checks might require the worker script spec
                      // later on.
                      const nsACString& aScriptSpec,
                      nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration,
-                     const nsAString& aDocumentId,
+                     const nsAString& aClientId,
                      bool aIsReload,
                      bool aMarkLaunchServiceWorkerEnd)
     : ExtendableFunctionalEventWorkerRunnable(
         aWorkerPrivate, aKeepAliveToken, aRegistration)
     , mInterceptedChannel(aChannel)
     , mScriptSpec(aScriptSpec)
-    , mClientId(aDocumentId)
+    , mClientId(aClientId)
     , mIsReload(aIsReload)
     , mMarkLaunchServiceWorkerEnd(aMarkLaunchServiceWorkerEnd)
     , mCacheMode(RequestCache::Default)
     , mRequestMode(RequestMode::No_cors)
     , mRequestRedirect(RequestRedirect::Follow)
     // By default we set it to same-origin since normal HTTP fetches always
     // send credentials to same-origin websites unless explicitly forbidden.
     , mRequestCredentials(RequestCredentials::Same_origin)
@@ -1633,17 +1633,21 @@ private:
 
     MOZ_ASSERT_IF(internalReq->IsNavigationRequest(),
                   request->Redirect() == RequestRedirect::Manual);
 
     RootedDictionary<FetchEventInit> init(aCx);
     init.mRequest = request;
     init.mBubbles = false;
     init.mCancelable = true;
-    if (!mClientId.IsEmpty()) {
+    // Only expose the FetchEvent.clientId on subresource requests for now.
+    // Once we implement .resultingClientId and .targetClientId we can then
+    // start exposing .clientId on non-subresource requests as well.  See
+    // bug 1264177.
+    if (!mClientId.IsEmpty() && !internalReq->IsNavigationRequest()) {
       init.mClientId = mClientId;
     }
     init.mIsReload = mIsReload;
     RefPtr<FetchEvent> event =
       FetchEvent::Constructor(globalObj, NS_LITERAL_STRING("fetch"), init, result);
     if (NS_WARN_IF(result.Failed())) {
       result.SuppressException();
       return false;
@@ -1679,18 +1683,17 @@ private:
 
 NS_IMPL_ISUPPORTS_INHERITED(FetchEventRunnable, WorkerRunnable, nsIHttpHeaderVisitor)
 
 } // anonymous namespace
 
 nsresult
 ServiceWorkerPrivate::SendFetchEvent(nsIInterceptedChannel* aChannel,
                                      nsILoadGroup* aLoadGroup,
-                                     const nsAString& aDocumentId,
-                                     bool aIsReload)
+                                     const nsAString& aClientId, bool aIsReload)
 {
   AssertIsOnMainThread();
 
   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
   if (NS_WARN_IF(!mInfo || !swm)) {
     return NS_ERROR_FAILURE;
   }
 
@@ -1757,17 +1760,17 @@ ServiceWorkerPrivate::SendFetchEvent(nsI
       "ServiceWorkerRegistrationInfo", registration, false));
 
   RefPtr<KeepAliveToken> token = CreateEventKeepAliveToken();
 
 
   RefPtr<FetchEventRunnable> r =
     new FetchEventRunnable(mWorkerPrivate, token, handle,
                            mInfo->ScriptSpec(), regInfo,
-                           aDocumentId, aIsReload, newWorkerCreated);
+                           aClientId, aIsReload, newWorkerCreated);
   rv = r->Init();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   if (mInfo->State() == ServiceWorkerState::Activating) {
     mPendingFunctionalEvents.AppendElement(r.forget());
     return NS_OK;
@@ -1906,17 +1909,17 @@ ServiceWorkerPrivate::SpawnWorkerIfNeede
   jsapi.Init();
   ErrorResult error;
   NS_ConvertUTF8toUTF16 scriptSpec(mInfo->ScriptSpec());
 
   mWorkerPrivate = WorkerPrivate::Constructor(jsapi.cx(),
                                               scriptSpec,
                                               false, WorkerTypeService,
                                               VoidString(),
-                                              mInfo->Scope(),
+                                              EmptyCString(),
                                               &info, error);
   if (NS_WARN_IF(error.Failed())) {
     return error.StealNSResult();
   }
 
   RenewKeepAliveToken(aWhy);
 
   if (aNewWorkerCreated) {
--- a/dom/workers/ServiceWorkerPrivate.h
+++ b/dom/workers/ServiceWorkerPrivate.h
@@ -117,20 +117,18 @@ public:
                         const nsAString& aBody,
                         const nsAString& aTag,
                         const nsAString& aIcon,
                         const nsAString& aData,
                         const nsAString& aBehavior,
                         const nsAString& aScope);
 
   nsresult
-  SendFetchEvent(nsIInterceptedChannel* aChannel,
-                 nsILoadGroup* aLoadGroup,
-                 const nsAString& aDocumentId,
-                 bool aIsReload);
+  SendFetchEvent(nsIInterceptedChannel* aChannel, nsILoadGroup* aLoadGroup,
+                 const nsAString& aClientId, bool aIsReload);
 
   void
   StoreISupports(nsISupports* aSupports);
 
   void
   RemoveISupports(nsISupports* aSupports);
 
   // This will terminate the current running worker thread and drop the