Bug 1148935 - Correctly reflect worker and sharedworker RequestContext values; r=smaug
☠☠ backed out by 53c66ab06d38 ☠ ☠
authorEhsan Akhgari <ehsan@mozilla.com>
Tue, 16 Jun 2015 21:21:08 -0400
changeset 281836 7b09594541f3ac6fdbd8043762bdda9d6d8fa53f
parent 281835 587e2801a2392a70bb40dcd646013fdde2d58f03
child 281837 ea7188e6713cfa4c91b5f3e046935b5faa4d4c79
push id897
push userjlund@mozilla.com
push dateMon, 14 Sep 2015 18:56:12 +0000
treeherdermozilla-release@9411e2d2b214 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1148935
milestone41.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 1148935 - Correctly reflect worker and sharedworker RequestContext values; r=smaug
dom/base/nsScriptLoader.cpp
dom/fetch/InternalRequest.cpp
dom/fetch/InternalRequest.h
dom/workers/RuntimeService.cpp
dom/workers/ScriptLoader.cpp
dom/workers/ScriptLoader.h
dom/workers/ServiceWorkerManager.cpp
dom/workers/ServiceWorkerScriptCache.cpp
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerPrivate.h
dom/workers/test/serviceworkers/fetch/context/context_test.js
dom/workers/test/serviceworkers/fetch/context/index.html
dom/workers/test/serviceworkers/fetch/context/parentsharedworker.js
dom/workers/test/serviceworkers/fetch/context/parentworker.js
dom/workers/test/serviceworkers/fetch/context/sharedworker.js
dom/workers/test/serviceworkers/fetch/context/worker.js
dom/workers/test/serviceworkers/mochitest.ini
--- a/dom/base/nsScriptLoader.cpp
+++ b/dom/base/nsScriptLoader.cpp
@@ -209,17 +209,17 @@ IsScriptEventHandler(nsIContent* aScript
 
 nsresult
 nsScriptLoader::CheckContentPolicy(nsIDocument* aDocument,
                                    nsISupports *aContext,
                                    nsIURI *aURI,
                                    const nsAString &aType)
 {
   int16_t shouldLoad = nsIContentPolicy::ACCEPT;
-  nsresult rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_SCRIPT,
+  nsresult rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_INTERNAL_SCRIPT,
                                           aURI,
                                           aDocument->NodePrincipal(),
                                           aContext,
                                           NS_LossyConvertUTF16toASCII(aType),
                                           nullptr,    //extra
                                           &shouldLoad,
                                           nsContentUtils::GetContentPolicy(),
                                           nsContentUtils::GetSecurityManager());
@@ -284,17 +284,17 @@ nsScriptLoader::StartLoad(nsScriptLoadRe
     return NS_OK;
   }
 
   nsCOMPtr<nsIChannel> channel;
   rv = NS_NewChannel(getter_AddRefs(channel),
                      aRequest->mURI,
                      mDocument,
                      nsILoadInfo::SEC_NORMAL,
-                     nsIContentPolicy::TYPE_SCRIPT,
+                     nsIContentPolicy::TYPE_INTERNAL_SCRIPT,
                      loadGroup,
                      prompter,
                      nsIRequest::LOAD_NORMAL |
                      nsIChannel::LOAD_CLASSIFY_URI);
 
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsIScriptElement *script = aRequest->mElement;
--- a/dom/fetch/InternalRequest.cpp
+++ b/dom/fetch/InternalRequest.cpp
@@ -108,19 +108,25 @@ InternalRequest::SetContentPolicyType(ns
 RequestContext
 InternalRequest::MapContentPolicyTypeToRequestContext(nsContentPolicyType aContentPolicyType)
 {
   RequestContext context = RequestContext::Internal;
   switch (aContentPolicyType) {
   case nsIContentPolicy::TYPE_OTHER:
     context = RequestContext::Internal;
     break;
-  case nsIContentPolicy::TYPE_SCRIPT:
+  case nsIContentPolicy::TYPE_INTERNAL_SCRIPT:
     context = RequestContext::Script;
     break;
+  case nsIContentPolicy::TYPE_INTERNAL_WORKER:
+    context = RequestContext::Worker;
+    break;
+  case nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER:
+    context = RequestContext::Sharedworker;
+    break;
   case nsIContentPolicy::TYPE_IMAGE:
     context = RequestContext::Image;
     break;
   case nsIContentPolicy::TYPE_STYLESHEET:
     context = RequestContext::Style;
     break;
   case nsIContentPolicy::TYPE_OBJECT:
     context = RequestContext::Object;
--- a/dom/fetch/InternalRequest.h
+++ b/dom/fetch/InternalRequest.h
@@ -48,32 +48,31 @@ namespace dom {
  * import            | Not supported by Gecko
  * internal          | TYPE_DOCUMENT, TYPE_XBL, TYPE_OTHER
  * location          |
  * manifest          | TYPE_WEB_MANIFEST
  * object            | TYPE_OBJECT
  * ping              | TYPE_PING
  * plugin            | TYPE_OBJECT_SUBREQUEST
  * prefetch          |
- * script            | TYPE_SCRIPT
- * sharedworker      |
+ * script            | TYPE_INTERNAL_SCRIPT
+ * sharedworker      | TYPE_INTERNAL_SHARED_WORKER
  * subresource       | Not supported by Gecko
  * style             | TYPE_STYLESHEET
  * track             | TYPE_INTERNAL_TRACK
  * video             | TYPE_INTERNAL_VIDEO
- * worker            |
+ * worker            | TYPE_INTERNAL_WORKER
  * xmlhttprequest    | TYPE_XMLHTTPREQUEST
  * xslt              | TYPE_XSLT
  *
  * TODO: Figure out if TYPE_REFRESH maps to anything useful
  * TODO: Figure out if TYPE_DTD maps to anything useful
  * TODO: Split TYPE_XMLHTTPREQUEST and TYPE_DATAREQUEST for EventSource
  * TODO: Figure out if TYPE_WEBSOCKET maps to anything useful
  * TODO: Differentiate between frame and iframe
- * TODO: Add content types for different kinds of workers
  * TODO: Add a content type for prefetch
  * TODO: Use the content type for manifest when it becomes available
  * TODO: Add a content type for location
  * TODO: Add a content type for hyperlink
  * TODO: Add a content type for form
  * TODO: Add a content type for favicon
  * TODO: Add a content type for download
  * TODO: Split TYPE_OBJECT into TYPE_EMBED and TYPE_OBJECT
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -2339,17 +2339,17 @@ RuntimeService::CreateSharedWorkerIntern
   MOZ_ASSERT(window);
 
   JSContext* cx = aGlobal.Context();
 
   WorkerLoadInfo loadInfo;
   nsresult rv = WorkerPrivate::GetLoadInfo(cx, window, nullptr, aScriptURL,
                                            false,
                                            WorkerPrivate::OverrideLoadGroup,
-                                           &loadInfo);
+                                           aType, &loadInfo);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return CreateSharedWorkerFromLoadInfo(cx, &loadInfo, aScriptURL, aName, aType,
                                         aSharedWorker);
 }
 
 nsresult
 RuntimeService::CreateSharedWorkerFromLoadInfo(JSContext* aCx,
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -90,33 +90,34 @@ ChannelFromScriptURL(nsIPrincipal* princ
                      nsIURI* baseURI,
                      nsIDocument* parentDoc,
                      nsILoadGroup* loadGroup,
                      nsIIOService* ios,
                      nsIScriptSecurityManager* secMan,
                      const nsAString& aScriptURL,
                      bool aIsMainScript,
                      WorkerScriptType aWorkerScriptType,
+                     nsContentPolicyType aContentPolicyType,
                      nsIChannel** aChannel)
 {
   AssertIsOnMainThread();
 
   nsresult rv;
   nsCOMPtr<nsIURI> uri;
   rv = nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(uri),
                                                  aScriptURL, parentDoc,
                                                  baseURI);
   if (NS_FAILED(rv)) {
     return NS_ERROR_DOM_SYNTAX_ERR;
   }
 
   // If we're part of a document then check the content load policy.
   if (parentDoc) {
     int16_t shouldLoad = nsIContentPolicy::ACCEPT;
-    rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_SCRIPT, uri,
+    rv = NS_CheckContentLoadPolicy(aContentPolicyType, uri,
                                    principal, parentDoc,
                                    NS_LITERAL_CSTRING("text/javascript"),
                                    nullptr, &shouldLoad,
                                    nsContentUtils::GetContentPolicy(),
                                    secMan);
     if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
       if (NS_FAILED(rv) || shouldLoad != nsIContentPolicy::REJECT_TYPE) {
         return rv = NS_ERROR_CONTENT_BLOCKED;
@@ -161,32 +162,32 @@ ChannelFromScriptURL(nsIPrincipal* princ
 
   nsCOMPtr<nsIChannel> channel;
   // If we have the document, use it
   if (parentDoc) {
     rv = NS_NewChannel(getter_AddRefs(channel),
                        uri,
                        parentDoc,
                        nsILoadInfo::SEC_NORMAL,
-                       nsIContentPolicy::TYPE_SCRIPT,
+                       aContentPolicyType,
                        loadGroup,
                        nullptr, // aCallbacks
                        flags,
                        ios);
   } else {
     // We must have a loadGroup with a load context for the principal to
     // traverse the channel correctly.
     MOZ_ASSERT(loadGroup);
     MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(loadGroup, principal));
 
     rv = NS_NewChannel(getter_AddRefs(channel),
                        uri,
                        principal,
                        nsILoadInfo::SEC_NORMAL,
-                       nsIContentPolicy::TYPE_SCRIPT,
+                       aContentPolicyType,
                        loadGroup,
                        nullptr, // aCallbacks
                        flags,
                        ios);
   }
 
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -802,17 +803,19 @@ private:
     NS_ASSERTION(secMan, "This should never be null!");
 
     ScriptLoadInfo& loadInfo = mLoadInfos[aIndex];
     nsresult& rv = loadInfo.mLoadResult;
 
     if (!channel) {
       rv = ChannelFromScriptURL(principal, baseURI, parentDoc, loadGroup, ios,
                                 secMan, loadInfo.mURL, IsMainWorkerScript(),
-                                mWorkerScriptType, getter_AddRefs(channel));
+                                mWorkerScriptType,
+                                mWorkerPrivate->ContentPolicyType(),
+                                getter_AddRefs(channel));
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
     }
 
     // We need to know which index we're on in OnStreamComplete so we know
     // where to put the result.
     nsCOMPtr<nsISupportsPRUint32> indexSupports =
@@ -1514,16 +1517,18 @@ public:
 
     nsCOMPtr<nsILoadGroup> loadGroup = mParentWorker->GetLoadGroup();
 
     nsCOMPtr<nsIChannel> channel;
     mResult =
       scriptloader::ChannelFromScriptURLMainThread(principal, baseURI,
                                                    parentDoc, loadGroup,
                                                    mScriptURL,
+                                                   // Nested workers are always dedicated.
+                                                   nsIContentPolicy::TYPE_INTERNAL_WORKER,
                                                    getter_AddRefs(channel));
     if (NS_SUCCEEDED(mResult)) {
       channel.forget(mChannel);
     }
 
     nsRefPtr<MainThreadStopSyncLoopRunnable> runnable =
       new MainThreadStopSyncLoopRunnable(mParentWorker,
                                          mSyncLoopTarget.forget(), true);
@@ -1725,27 +1730,29 @@ BEGIN_WORKERS_NAMESPACE
 namespace scriptloader {
 
 nsresult
 ChannelFromScriptURLMainThread(nsIPrincipal* aPrincipal,
                                nsIURI* aBaseURI,
                                nsIDocument* aParentDoc,
                                nsILoadGroup* aLoadGroup,
                                const nsAString& aScriptURL,
+                               nsContentPolicyType aContentPolicyType,
                                nsIChannel** aChannel)
 {
   AssertIsOnMainThread();
 
   nsCOMPtr<nsIIOService> ios(do_GetIOService());
 
   nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
   NS_ASSERTION(secMan, "This should never be null!");
 
   return ChannelFromScriptURL(aPrincipal, aBaseURI, aParentDoc, aLoadGroup,
-                              ios, secMan, aScriptURL, true, WorkerScript, aChannel);
+                              ios, secMan, aScriptURL, true, WorkerScript,
+                              aContentPolicyType, aChannel);
 }
 
 nsresult
 ChannelFromScriptURLWorkerThread(JSContext* aCx,
                                  WorkerPrivate* aParent,
                                  const nsAString& aScriptURL,
                                  nsIChannel** aChannel)
 {
--- a/dom/workers/ScriptLoader.h
+++ b/dom/workers/ScriptLoader.h
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_workers_scriptloader_h__
 #define mozilla_dom_workers_scriptloader_h__
 
 #include "Workers.h"
+#include "nsIContentPolicyBase.h"
 
 class nsIPrincipal;
 class nsIURI;
 class nsIDocument;
 class nsILoadGroup;
 class nsString;
 class nsIChannel;
 
@@ -32,16 +33,17 @@ enum WorkerScriptType {
 namespace scriptloader {
 
 nsresult
 ChannelFromScriptURLMainThread(nsIPrincipal* aPrincipal,
                                nsIURI* aBaseURI,
                                nsIDocument* aParentDoc,
                                nsILoadGroup* aLoadGroup,
                                const nsAString& aScriptURL,
+                               nsContentPolicyType aContentPolicyType,
                                nsIChannel** aChannel);
 
 nsresult
 ChannelFromScriptURLWorkerThread(JSContext* aCx,
                                  WorkerPrivate* aParent,
                                  const nsAString& aScriptURL,
                                  nsIChannel** aChannel);
 
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -2545,16 +2545,17 @@ ServiceWorkerManager::CreateServiceWorke
   jsapi.Init(aWindow);
   JSContext* cx = jsapi.cx();
 
   WorkerLoadInfo loadInfo;
   nsresult rv = WorkerPrivate::GetLoadInfo(cx, aWindow, nullptr,
                                            NS_ConvertUTF8toUTF16(aInfo->ScriptSpec()),
                                            false,
                                            WorkerPrivate::OverrideLoadGroup,
+                                           WorkerTypeService,
                                            &loadInfo);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   MOZ_ASSERT(!aInfo->CacheName().IsEmpty());
   loadInfo.mServiceWorkerCacheName = aInfo->CacheName();
   loadInfo.mServiceWorkerID = aInfo->ID();
--- a/dom/workers/ServiceWorkerScriptCache.cpp
+++ b/dom/workers/ServiceWorkerScriptCache.cpp
@@ -83,20 +83,23 @@ public:
     AssertIsOnMainThread();
 
     nsCOMPtr<nsIURI> uri;
     nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, nullptr, nullptr);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
+    // Note that because there is no "serviceworker" RequestContext type, we can
+    // use the external TYPE_SCRIPT content policy types when loading a service
+    // worker.
     rv = NS_NewChannel(getter_AddRefs(mChannel),
                        uri, aPrincipal,
                        nsILoadInfo::SEC_NORMAL,
-                       nsIContentPolicy::TYPE_SCRIPT); // FIXME(nsm): TYPE_SERVICEWORKER
+                       nsIContentPolicy::TYPE_SCRIPT);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     nsLoadFlags flags;
     rv = mChannel->GetLoadFlags(&flags);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -4837,17 +4837,17 @@ WorkerPrivate::Constructor(JSContext* aC
                 aSharedWorkerName.IsEmpty());
 
   Maybe<WorkerLoadInfo> stackLoadInfo;
   if (!aLoadInfo) {
     stackLoadInfo.emplace();
 
     nsresult rv = GetLoadInfo(aCx, nullptr, parent, aScriptURL,
                               aIsChromeWorker, InheritLoadGroup,
-                              stackLoadInfo.ptr());
+                              aWorkerType, stackLoadInfo.ptr());
     if (NS_FAILED(rv)) {
       scriptloader::ReportLoadError(aCx, aScriptURL, rv, !parent);
       aRv.Throw(rv);
       return nullptr;
     }
 
     aLoadInfo = stackLoadInfo.ptr();
   }
@@ -4895,16 +4895,17 @@ WorkerPrivate::Constructor(JSContext* aC
 }
 
 // static
 nsresult
 WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow,
                            WorkerPrivate* aParent, const nsAString& aScriptURL,
                            bool aIsChromeWorker,
                            LoadGroupBehavior aLoadGroupBehavior,
+                           WorkerType aWorkerType,
                            WorkerLoadInfo* aLoadInfo)
 {
   using namespace mozilla::dom::workers::scriptloader;
   using mozilla::dom::indexedDB::IDBFactory;
 
   MOZ_ASSERT(aCx);
   MOZ_ASSERT_IF(NS_IsMainThread(), aCx == nsContentUtils::GetCurrentJSContext());
 
@@ -5140,16 +5141,17 @@ WorkerPrivate::GetLoadInfo(JSContext* aC
       OverrideLoadInfoLoadGroup(loadInfo);
     }
     MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(loadInfo.mLoadGroup,
                                             loadInfo.mPrincipal));
 
     rv = ChannelFromScriptURLMainThread(loadInfo.mPrincipal, loadInfo.mBaseURI,
                                         document, loadInfo.mLoadGroup,
                                         aScriptURL,
+                                        ContentPolicyType(aWorkerType),
                                         getter_AddRefs(loadInfo.mChannel));
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = NS_GetFinalChannelURI(loadInfo.mChannel,
                                getter_AddRefs(loadInfo.mResolvedScriptURI));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_workers_workerprivate_h__
 #define mozilla_dom_workers_workerprivate_h__
 
 #include "Workers.h"
 
+#include "nsIContentPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsILoadGroup.h"
 #include "nsIWorkerDebugger.h"
 #include "nsPIDOMWindow.h"
 
 #include "mozilla/CondVar.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/TimeStamp.h"
@@ -729,16 +730,38 @@ public:
   }
 
   bool
   IsServiceWorker() const
   {
     return mWorkerType == WorkerTypeService;
   }
 
+  nsContentPolicyType
+  ContentPolicyType() const
+  {
+    return ContentPolicyType(mWorkerType);
+  }
+
+  static nsContentPolicyType
+  ContentPolicyType(WorkerType aWorkerType)
+  {
+    switch (aWorkerType) {
+    case WorkerTypeDedicated:
+      return nsIContentPolicy::TYPE_INTERNAL_WORKER;
+    case WorkerTypeShared:
+      return nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER;
+    case WorkerTypeService:
+      return nsIContentPolicy::TYPE_SCRIPT;
+    default:
+      MOZ_ASSERT_UNREACHABLE("Invalid worker type");
+      return nsIContentPolicy::TYPE_INVALID;
+    }
+  }
+
   const nsCString&
   SharedWorkerName() const
   {
     return mSharedWorkerName;
   }
 
   uint64_t
   NextMessagePortSerial()
@@ -964,17 +987,18 @@ public:
   {
     InheritLoadGroup,
     OverrideLoadGroup
   };
 
   static nsresult
   GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow, WorkerPrivate* aParent,
               const nsAString& aScriptURL, bool aIsChromeWorker,
-              LoadGroupBehavior aLoadGroupBehavior, WorkerLoadInfo* aLoadInfo);
+              LoadGroupBehavior aLoadGroupBehavior, WorkerType aWorkerType,
+              WorkerLoadInfo* aLoadInfo);
 
   static void
   OverrideLoadInfoLoadGroup(WorkerLoadInfo& aLoadInfo);
 
   WorkerDebugger*
   Debugger() const
   {
     AssertIsOnMainThread();
--- a/dom/workers/test/serviceworkers/fetch/context/context_test.js
+++ b/dom/workers/test/serviceworkers/fetch/context/context_test.js
@@ -65,16 +65,32 @@ self.addEventListener("fetch", function(
   } else if (event.request.url.indexOf("track") >= 0) {
     respondToServiceWorker(event, "track");
   } else if (event.request.url.indexOf("xhr") >= 0) {
     if (event.request.context == "xmlhttprequest") {
       event.respondWith(new Response(""));
     }
   } else if (event.request.url.indexOf("xslt") >= 0) {
     respondToServiceWorker(event, "xslt");
+   } else if (event.request.url.indexOf("myworker") >= 0) {
+     if (event.request.context == "worker") {
+       event.respondWith(fetch("worker.js"));
+     }
+   } else if (event.request.url.indexOf("myparentworker") >= 0) {
+     if (event.request.context == "worker") {
+       event.respondWith(fetch("parentworker.js"));
+     }
+   } else if (event.request.url.indexOf("mysharedworker") >= 0) {
+     if (event.request.context == "sharedworker") {
+       event.respondWith(fetch("sharedworker.js"));
+     }
+   } else if (event.request.url.indexOf("myparentsharedworker") >= 0) {
+     if (event.request.context == "sharedworker") {
+       event.respondWith(fetch("parentsharedworker.js"));
+     }
   } else if (event.request.url.indexOf("cache") >= 0) {
     var cache;
     var origContext = event.request.context;
     event.respondWith(caches.open("cache")
       .then(function(c) {
         cache = c;
         // Store the Request in the cache.
         return cache.put(event.request, new Response("fake"));
--- a/dom/workers/test/serviceworkers/fetch/context/index.html
+++ b/dom/workers/test/serviceworkers/fetch/context/index.html
@@ -336,16 +336,68 @@
           // Without this, the test leaks in e10s!
           iframe.parentNode.removeChild(iframe);
           resolve();
         }
       }, false);
     });
   }
 
+  function testWorker() {
+    return new Promise(function(resolve, reject) {
+      var worker = new Worker("myworker");
+      worker.onmessage = function(e) {
+        if (e.data == "ack") {
+          worker.terminate();
+          resolve();
+        }
+      };
+      worker.onerror = reject;
+    });
+  }
+
+  function testNestedWorker() {
+    return new Promise(function(resolve, reject) {
+      var worker = new Worker("myparentworker");
+      worker.onmessage = function(e) {
+        if (e.data == "ack") {
+          worker.terminate();
+          resolve();
+        }
+      };
+      worker.onerror = reject;
+    });
+  }
+
+  function testSharedWorker() {
+    return new Promise(function(resolve, reject) {
+      var worker = new SharedWorker("mysharedworker");
+      worker.port.start();
+      worker.port.onmessage = function(e) {
+        if (e.data == "ack") {
+          resolve();
+        }
+      };
+      worker.onerror = reject;
+    });
+  }
+
+  function testNestedWorkerInSharedWorker() {
+    return new Promise(function(resolve, reject) {
+      var worker = new SharedWorker("myparentsharedworker");
+      worker.port.start();
+      worker.port.onmessage = function(e) {
+        if (e.data == "ack") {
+          resolve();
+        }
+      };
+      worker.onerror = reject;
+    });
+  }
+
   function testCache() {
     return new Promise(function(resolve, reject) {
       // Issue an XHR that will be intercepted by the SW in order to start off
       // the test with a RequestContext value that is not the default ("fetch").
       // This needs to run inside a fetch event handler because synthesized
       // RequestContext objects can only have the "fetch" context, and we'd
       // prefer to test the more general case of some other RequestContext value.
       var xhr = new XMLHttpRequest();
@@ -378,16 +430,20 @@
     testInternal(),
     testPing(),
     testPlugin(),
     testScript(),
     testStyle(),
     testTrack(),
     testXHR(),
     testXSLT(),
+    testWorker(),
+    testNestedWorker(),
+    testSharedWorker(),
+    testNestedWorkerInSharedWorker(),
 
     // Also, test to see if the type of the request can be persisted in the database.
     testCache(),
   ])
   .then(function() {
     finish();
   }, function(e) {
     ok(false, "A promise was rejected: " + e);
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/fetch/context/parentsharedworker.js
@@ -0,0 +1,8 @@
+onconnect = function(e) {
+  e.ports[0].start();
+  var worker = new Worker("myworker?shared");
+  worker.onmessage = function(e2) {
+    e.ports[0].postMessage(e2.data);
+    self.close();
+  };
+};
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/fetch/context/parentworker.js
@@ -0,0 +1,4 @@
+var worker = new Worker("myworker");
+worker.onmessage = function(e) {
+  postMessage(e.data);
+};
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/fetch/context/sharedworker.js
@@ -0,0 +1,5 @@
+onconnect = function(e) {
+  e.ports[0].start();
+  e.ports[0].postMessage("ack");
+  self.close();
+};
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/fetch/context/worker.js
@@ -0,0 +1,1 @@
+postMessage("ack");
--- a/dom/workers/test/serviceworkers/mochitest.ini
+++ b/dom/workers/test/serviceworkers/mochitest.ini
@@ -33,16 +33,20 @@ support-files =
   fetch/context/register.html
   fetch/context/unregister.html
   fetch/context/context_test.js
   fetch/context/realimg.jpg
   fetch/context/realaudio.ogg
   fetch/context/beacon.sjs
   fetch/context/csp-violate.sjs
   fetch/context/ping.html
+  fetch/context/worker.js
+  fetch/context/parentworker.js
+  fetch/context/sharedworker.js
+  fetch/context/parentsharedworker.js
   fetch/context/xml.xml
   fetch/https/index.html
   fetch/https/register.html
   fetch/https/unregister.html
   fetch/https/https_test.js
   fetch/https/clonedresponse/index.html
   fetch/https/clonedresponse/register.html
   fetch/https/clonedresponse/unregister.html