Bug 1364297 - Worker and SharedWorker constructors have an optional WorkerOptions parameter, r=smaug
authorAndrea Marchesini <amarchesini@mozilla.com>
Wed, 17 May 2017 16:48:54 +0200
changeset 406954 df81d965473664a0dae04cf629ef174ae9795c94
parent 406953 d8071b5a52f729ff774118a6e6a9c7b5e9dbce74
child 406955 d52a1c7cf0a3b3ec9019e0d5562b47b11866024c
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1364297
milestone55.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 1364297 - Worker and SharedWorker constructors have an optional WorkerOptions parameter, r=smaug
dom/webidl/DedicatedWorkerGlobalScope.webidl
dom/webidl/SharedWorker.webidl
dom/webidl/Worker.webidl
dom/workers/SharedWorker.cpp
dom/workers/SharedWorker.h
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerPrivate.h
dom/workers/WorkerScope.cpp
dom/workers/WorkerScope.h
testing/web-platform/tests/XMLHttpRequest/open-url-redirected-worker-origin.htm
testing/web-platform/tests/workers/constructors/SharedWorker/null-arguments.html
testing/web-platform/tests/workers/constructors/Worker/unexpected-self-properties.worker.js
--- a/dom/webidl/DedicatedWorkerGlobalScope.webidl
+++ b/dom/webidl/DedicatedWorkerGlobalScope.webidl
@@ -10,15 +10,17 @@
  * Software ASA.
  * You are granted a license to use, reproduce and create derivative works of
  * this document.
  */
 
 [Global=(Worker,DedicatedWorker),
  Exposed=DedicatedWorker]
 interface DedicatedWorkerGlobalScope : WorkerGlobalScope {
+  readonly attribute DOMString name;
+
   [Throws]
   void postMessage(any message, optional sequence<object> transfer = []);
 
   void close();
 
   attribute EventHandler onmessage;
 };
--- a/dom/webidl/SharedWorker.webidl
+++ b/dom/webidl/SharedWorker.webidl
@@ -1,12 +1,12 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/.
  */
 
-[Constructor(USVString scriptURL, optional DOMString name)]
+[Constructor(USVString scriptURL, optional (DOMString or WorkerOptions) options)]
 interface SharedWorker : EventTarget {
     readonly attribute MessagePort port;
 };
 
 SharedWorker implements AbstractWorker;
--- a/dom/webidl/Worker.webidl
+++ b/dom/webidl/Worker.webidl
@@ -7,27 +7,33 @@
  * http://www.whatwg.org/specs/web-apps/current-work/multipage/workers.html
  *
  * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and Opera
  * Software ASA.
  * You are granted a license to use, reproduce and create derivative works of
  * this document.
  */
 
-[Constructor(USVString scriptURL),
+[Constructor(USVString scriptURL, optional WorkerOptions options),
  Func="mozilla::dom::workers::WorkerPrivate::WorkerAvailable",
  Exposed=(Window,DedicatedWorker,SharedWorker,System)]
 interface Worker : EventTarget {
   void terminate();
 
   [Throws]
   void postMessage(any message, optional sequence<object> transfer = []);
 
   attribute EventHandler onmessage;
 };
 
 Worker implements AbstractWorker;
 
+dictionary WorkerOptions {
+  // WorkerType type = "classic"; TODO: Bug 1247687
+  // RequestCredentials credentials = "omit"; // credentials is only used if type is "module" TODO: Bug 1247687
+  DOMString name = "";
+};
+
 [Constructor(USVString scriptURL),
  Func="mozilla::dom::workers::ChromeWorkerPrivate::WorkerAvailable",
  Exposed=(Window,DedicatedWorker,SharedWorker,System)]
 interface ChromeWorker : Worker {
 };
--- a/dom/workers/SharedWorker.cpp
+++ b/dom/workers/SharedWorker.cpp
@@ -7,16 +7,17 @@
 #include "SharedWorker.h"
 
 #include "nsPIDOMWindow.h"
 
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/MessagePort.h"
 #include "mozilla/dom/SharedWorkerBinding.h"
+#include "mozilla/dom/WorkerBinding.h"
 #include "mozilla/Telemetry.h"
 #include "nsContentUtils.h"
 #include "nsIClassInfoImpl.h"
 #include "nsIDOMEvent.h"
 
 #include "RuntimeService.h"
 #include "WorkerPrivate.h"
 
@@ -44,30 +45,33 @@ SharedWorker::~SharedWorker()
 {
   AssertIsOnMainThread();
 }
 
 // static
 already_AddRefed<SharedWorker>
 SharedWorker::Constructor(const GlobalObject& aGlobal,
                           const nsAString& aScriptURL,
-                          const mozilla::dom::Optional<nsAString>& aName,
+                          const StringOrWorkerOptions& aOptions,
                           ErrorResult& aRv)
 {
   AssertIsOnMainThread();
 
   RuntimeService* rts = RuntimeService::GetOrCreateService();
   if (!rts) {
     aRv = NS_ERROR_NOT_AVAILABLE;
     return nullptr;
   }
 
   nsCString name;
-  if (aName.WasPassed()) {
-    name = NS_ConvertUTF16toUTF8(aName.Value());
+  if (aOptions.IsString()) {
+    name = NS_ConvertUTF16toUTF8(aOptions.GetAsString());
+  } else {
+    MOZ_ASSERT(aOptions.IsWorkerOptions());
+    name = NS_ConvertUTF16toUTF8(aOptions.GetAsWorkerOptions().mName);
   }
 
   RefPtr<SharedWorker> sharedWorker;
   nsresult rv = rts->CreateSharedWorker(aGlobal, aScriptURL, name,
                                         getter_AddRefs(sharedWorker));
   if (NS_FAILED(rv)) {
     aRv = rv;
     return nullptr;
--- a/dom/workers/SharedWorker.h
+++ b/dom/workers/SharedWorker.h
@@ -15,16 +15,17 @@
 class nsIDOMEvent;
 class nsPIDOMWindowInner;
 
 namespace mozilla {
 class EventChainPreVisitor;
 
 namespace dom {
 class MessagePort;
+class StringOrWorkerOptions;
 }
 } // namespace mozilla
 
 BEGIN_WORKERS_NAMESPACE
 
 class RuntimeService;
 class WorkerPrivate;
 
@@ -38,17 +39,17 @@ class SharedWorker final : public DOMEve
   RefPtr<WorkerPrivate> mWorkerPrivate;
   RefPtr<MessagePort> mMessagePort;
   nsTArray<nsCOMPtr<nsIDOMEvent>> mFrozenEvents;
   bool mFrozen;
 
 public:
   static already_AddRefed<SharedWorker>
   Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL,
-              const Optional<nsAString>& aName, ErrorResult& aRv);
+              const StringOrWorkerOptions& aOptions, ErrorResult& aRv);
 
   MessagePort*
   Port();
 
   bool
   IsFrozen() const
   {
     return mFrozen;
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -2734,19 +2734,17 @@ WorkerPrivateParent<Derived>::WorkerPriv
   mWorkerName(aWorkerName), mLoadingWorkerScript(false),
   mBusyCount(0), mParentWindowPausedDepth(0), mParentStatus(Pending),
   mParentFrozen(false), mIsChromeWorker(aIsChromeWorker),
   mMainThreadObjectsForgotten(false), mIsSecureContext(false),
   mWorkerType(aWorkerType),
   mCreationTimeStamp(TimeStamp::Now()),
   mCreationTimeHighRes((double)PR_Now() / PR_USEC_PER_MSEC)
 {
-  MOZ_ASSERT_IF(!IsDedicatedWorker(),
-                !aWorkerName.IsVoid() && NS_IsMainThread());
-  MOZ_ASSERT_IF(IsDedicatedWorker(), aWorkerName.IsEmpty());
+  MOZ_ASSERT_IF(!IsDedicatedWorker(), NS_IsMainThread());
 
   if (aLoadInfo.mWindow) {
     AssertIsOnMainThread();
     MOZ_ASSERT(aLoadInfo.mWindow->IsInnerWindow(),
                "Should have inner window here!");
     BindToOwner(aLoadInfo.mWindow);
   }
 
@@ -4442,19 +4440,16 @@ WorkerPrivate::WorkerPrivate(WorkerPriva
   , mPendingEventQueueClearing(false)
   , mCancelAllPendingRunnables(false)
   , mPeriodicGCTimerRunning(false)
   , mIdleGCTimerRunning(false)
   , mWorkerScriptExecutedSuccessfully(false)
   , mFetchHandlerWasAdded(false)
   , mOnLine(false)
 {
-  MOZ_ASSERT_IF(!IsDedicatedWorker(), !aWorkerName.IsVoid());
-  MOZ_ASSERT_IF(IsDedicatedWorker(), aWorkerName.IsEmpty());
-
   if (aParent) {
     aParent->AssertIsOnWorkerThread();
     aParent->GetAllPreferences(mPreferences);
     mOnLine = aParent->OnLine();
   }
   else {
     AssertIsOnMainThread();
     RuntimeService::GetDefaultPreferences(mPreferences);
@@ -4501,20 +4496,22 @@ WorkerPrivate::~WorkerPrivate()
 {
   mWorkerControlEventTarget->ForgetWorkerPrivate(this);
 }
 
 // static
 already_AddRefed<WorkerPrivate>
 WorkerPrivate::Constructor(const GlobalObject& aGlobal,
                            const nsAString& aScriptURL,
+                           const WorkerOptions& aOptions,
                            ErrorResult& aRv)
 {
   return WorkerPrivate::Constructor(aGlobal, aScriptURL, false,
-                                    WorkerTypeDedicated, EmptyCString(),
+                                    WorkerTypeDedicated,
+                                    NS_ConvertUTF16toUTF8(aOptions.mName),
                                     nullptr, aRv);
 }
 
 // static
 bool
 WorkerPrivate::WorkerAvailable(JSContext* aCx, JSObject* /* unused */)
 {
   // If we're already on a worker workers are clearly enabled.
@@ -4583,22 +4580,16 @@ WorkerPrivate::Constructor(JSContext* aC
                           nullptr :
                           GetCurrentThreadWorkerPrivate();
   if (parent) {
     parent->AssertIsOnWorkerThread();
   } else {
     AssertIsOnMainThread();
   }
 
-  // Only service and shared workers can have names.
-  MOZ_ASSERT_IF(aWorkerType != WorkerTypeDedicated,
-                !aWorkerName.IsVoid());
-  MOZ_ASSERT_IF(aWorkerType == WorkerTypeDedicated,
-                aWorkerName.IsEmpty());
-
   Maybe<WorkerLoadInfo> stackLoadInfo;
   if (!aLoadInfo) {
     stackLoadInfo.emplace();
 
     nsresult rv = GetLoadInfo(aCx, nullptr, parent, aScriptURL,
                               aIsChromeWorker, InheritLoadGroup,
                               aWorkerType, stackLoadInfo.ptr());
     aRv.MightThrowJSException();
@@ -6916,17 +6907,17 @@ WorkerPrivate::GetOrCreateGlobalScope(JS
 
   if (!mScope) {
     RefPtr<WorkerGlobalScope> globalScope;
     if (IsSharedWorker()) {
       globalScope = new SharedWorkerGlobalScope(this, WorkerName());
     } else if (IsServiceWorker()) {
       globalScope = new ServiceWorkerGlobalScope(this, ServiceWorkerScope());
     } else {
-      globalScope = new DedicatedWorkerGlobalScope(this);
+      globalScope = new DedicatedWorkerGlobalScope(this, WorkerName());
     }
 
     JS::Rooted<JSObject*> global(aCx);
     NS_ENSURE_TRUE(globalScope->WrapGlobalObject(aCx, &global), nullptr);
 
     JSAutoCompartment ac(aCx, global);
 
     // RegisterBindings() can spin a nested event loop so we have to set mScope
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -64,16 +64,17 @@ class ThrottledEventQueue;
 namespace dom {
 class Function;
 class MessagePort;
 class MessagePortIdentifier;
 class PromiseNativeHandler;
 class StructuredCloneHolder;
 class WorkerDebuggerGlobalScope;
 class WorkerGlobalScope;
+struct WorkerOptions;
 } // namespace dom
 namespace ipc {
 class PrincipalInfo;
 } // namespace ipc
 } // namespace mozilla
 
 struct PRThread;
 
@@ -261,17 +262,17 @@ protected:
   // The worker is owned by its thread, which is represented here.  This is set
   // in Construct() and emptied by WorkerFinishedRunnable, and conditionally
   // traversed by the cycle collector if the busy count is zero.
   RefPtr<WorkerPrivate> mSelfRef;
 
   WorkerPrivateParent(WorkerPrivate* aParent,
                       const nsAString& aScriptURL, bool aIsChromeWorker,
                       WorkerType aWorkerType,
-                      const nsACString& aSharedWorkerName,
+                      const nsACString& aWorkerName,
                       WorkerLoadInfo& aLoadInfo);
 
   ~WorkerPrivateParent();
 
 private:
   Derived*
   ParentAsWorkerPrivate() const
   {
@@ -833,17 +834,16 @@ public:
       MOZ_ASSERT_UNREACHABLE("Invalid worker type");
       return nsIContentPolicy::TYPE_INVALID;
     }
   }
 
   const nsCString&
   WorkerName() const
   {
-    MOZ_ASSERT(IsSharedWorker());
     return mWorkerName;
   }
 
   bool
   IsStorageAllowed() const
   {
     return mLoadInfo.mStorageAllowed;
   }
@@ -1048,27 +1048,28 @@ class WorkerPrivate : public WorkerPriva
   bool mOnLine;
 
 protected:
   ~WorkerPrivate();
 
 public:
   static already_AddRefed<WorkerPrivate>
   Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL,
+              const WorkerOptions& aOptions,
               ErrorResult& aRv);
 
   static already_AddRefed<WorkerPrivate>
   Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL,
               bool aIsChromeWorker, WorkerType aWorkerType,
-              const nsACString& aSharedWorkerName,
+              const nsACString& aWorkerName,
               WorkerLoadInfo* aLoadInfo, ErrorResult& aRv);
 
   static already_AddRefed<WorkerPrivate>
   Constructor(JSContext* aCx, const nsAString& aScriptURL, bool aIsChromeWorker,
-              WorkerType aWorkerType, const nsACString& aSharedWorkerName,
+              WorkerType aWorkerType, const nsACString& aWorkerName,
               WorkerLoadInfo* aLoadInfo, ErrorResult& aRv);
 
   static bool
   WorkerAvailable(JSContext* /* unused */, JSObject* /* unused */);
 
   enum LoadGroupBehavior
   {
     InheritLoadGroup,
@@ -1457,17 +1458,17 @@ public:
   // the worker thread.  Implement nsICancelableRunnable if you wish to take
   // action on cancelation.
   nsIEventTarget*
   ControlEventTarget();
 
 private:
   WorkerPrivate(WorkerPrivate* aParent,
                 const nsAString& aScriptURL, bool aIsChromeWorker,
-                WorkerType aWorkerType, const nsACString& aSharedWorkerName,
+                WorkerType aWorkerType, const nsACString& aWorkerName,
                 WorkerLoadInfo& aLoadInfo);
 
   bool
   MayContinueRunning()
   {
     AssertIsOnWorkerThread();
 
     Status status;
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -484,18 +484,20 @@ WorkerGlobalScope::CreateImageBitmap(JSC
     return ImageBitmap::Create(this, aImage, aOffset, aLength, aFormat, aLayout,
                                aRv);
   } else {
     aRv.Throw(NS_ERROR_TYPE_ERR);
     return nullptr;
   }
 }
 
-DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate)
-: WorkerGlobalScope(aWorkerPrivate)
+DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate,
+                                                       const nsCString& aName)
+  : WorkerGlobalScope(aWorkerPrivate)
+  , mName(aName)
 {
 }
 
 bool
 DedicatedWorkerGlobalScope::WrapGlobalObject(JSContext* aCx,
                                              JS::MutableHandle<JSObject*> aReflector)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
--- a/dom/workers/WorkerScope.h
+++ b/dom/workers/WorkerScope.h
@@ -202,25 +202,33 @@ public:
   {
     MOZ_ASSERT(mWindowInteractionsAllowed > 0);
     mWindowInteractionsAllowed--;
   }
 };
 
 class DedicatedWorkerGlobalScope final : public WorkerGlobalScope
 {
+  const nsCString mName;
+
   ~DedicatedWorkerGlobalScope() { }
 
 public:
-  explicit DedicatedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate);
+  DedicatedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate,
+                             const nsCString& aName);
 
   virtual bool
   WrapGlobalObject(JSContext* aCx,
                    JS::MutableHandle<JSObject*> aReflector) override;
 
+  void GetName(DOMString& aName) const
+  {
+    aName.AsAString() = NS_ConvertUTF8toUTF16(mName);
+  }
+
   void
   PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
               const Sequence<JSObject*>& aTransferable,
               ErrorResult& aRv);
 
   void
   Close(JSContext* aCx);
 
--- a/testing/web-platform/tests/XMLHttpRequest/open-url-redirected-worker-origin.htm
+++ b/testing/web-platform/tests/XMLHttpRequest/open-url-redirected-worker-origin.htm
@@ -13,17 +13,17 @@
         var expectations = {
             'Referer header': 'Referer: '+(location.href.replace(/[^/]*$/, ''))+"resources/workerxhr-origin-referrer.js\n",
             'Origin header': 'Origin: '+location.protocol+'//'+location.hostname+((location.port === "")?"":":"+location.port)+'\n',
             'Request URL test' : (location.href.replace(/[^/]*$/, ''))+'resources/requri.py?full'
         }
         // now start the worker
         var finalWorkerURL = "workerxhr-origin-referrer.js";
         var url = "resources/redirect.py?location=" + encodeURIComponent(finalWorkerURL);
-        var worker = new Worker(url, true)
+        var worker = new Worker(url)
         worker.onmessage = function (e) {
             var subtest = async_test(e.data.test)
             subtest.step(function(){
                 var thisExpectation = expectations[e.data.test]
                 delete expectations[e.data.test]
                 assert_equals(e.data.result, thisExpectation)
                 subtest.done()
             })
--- a/testing/web-platform/tests/workers/constructors/SharedWorker/null-arguments.html
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/null-arguments.html
@@ -9,17 +9,17 @@ onconnect = function(e) {
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <div id="log"></div>
 <script>
 (async_test()).step(function() {
   var worker = new SharedWorker(null, null);
   worker.port.addEventListener('message', this.step_func(function(e) {
     assert_equals(e.data[0], 'null', 'first arg');
-    assert_equals(e.data[1], 'null', 'second arg');
+    assert_equals(e.data[1], '', 'second arg');
     this.done();
   }), false);
   worker.port.start();
 });
 </script>
 <!--
 */
-//-->
\ No newline at end of file
+//-->
--- a/testing/web-platform/tests/workers/constructors/Worker/unexpected-self-properties.worker.js
+++ b/testing/web-platform/tests/workers/constructors/Worker/unexpected-self-properties.worker.js
@@ -1,11 +1,11 @@
 importScripts("/resources/testharness.js");
 
-var unexpected = ['open', 'print', 'stop', 'getComputedStyle', 'getSelection', 'releaseEvents', 'captureEvents', 'alert', 'confirm', 'prompt', 'addEventStream', 'removeEventStream', 'back', 'forward', 'attachEvent', 'detachEvent', 'navigate', 'DOMParser', 'XMLSerializer', 'XPathEvaluator', 'XSLTProcessor', 'opera', 'Image', 'Option', 'frames', 'Audio', 'SVGUnitTypes', 'SVGZoomAndPan', 'java', 'netscape', 'sun', 'Packages', 'ByteArray', 'closed', 'defaultStatus', 'document', 'event', 'frameElement', 'history', 'innerHeight', 'innerWidth', 'name', 'opener', 'outerHeight', 'outerWidth', 'pageXOffset', 'pageYOffset', 'parent', 'screen', 'screenLeft', 'screenTop', 'screenX', 'screenY', 'status', 'top', 'window', 'length']; // iterated window in opera and removed expected ones
+var unexpected = ['open', 'print', 'stop', 'getComputedStyle', 'getSelection', 'releaseEvents', 'captureEvents', 'alert', 'confirm', 'prompt', 'addEventStream', 'removeEventStream', 'back', 'forward', 'attachEvent', 'detachEvent', 'navigate', 'DOMParser', 'XMLSerializer', 'XPathEvaluator', 'XSLTProcessor', 'opera', 'Image', 'Option', 'frames', 'Audio', 'SVGUnitTypes', 'SVGZoomAndPan', 'java', 'netscape', 'sun', 'Packages', 'ByteArray', 'closed', 'defaultStatus', 'document', 'event', 'frameElement', 'history', 'innerHeight', 'innerWidth', 'opener', 'outerHeight', 'outerWidth', 'pageXOffset', 'pageYOffset', 'parent', 'screen', 'screenLeft', 'screenTop', 'screenX', 'screenY', 'status', 'top', 'window', 'length']; // iterated window in opera and removed expected ones
 for (var i = 0; i < unexpected.length; ++i) {
   var property = unexpected[i];
   test(function() {
     assert_false(property in self);
   }, "existence of " + property);
 }
 
 done();