Bug 920015 - Expose DOM URL to js modules, r=ehsan, f=emk, r=bz, r=bholley, r=smaug
authorAndrea Marchesini <amarchesini@mozilla.com>
Thu, 10 Oct 2013 08:56:01 +0200
changeset 164111 977afa826c5e2f87ea59966aefed114b3667063d
parent 164110 aa11ee736eff3900f2ffda88ece71ad718ab9711
child 164120 863ebb578c978d8f4aa7768588beac6d6fd6c309
child 164168 f1c6028203dec8d6c6a6669a7e2d47fb99e4d0dc
push id3066
push userakeybl@mozilla.com
push dateMon, 09 Dec 2013 19:58:46 +0000
treeherdermozilla-beta@a31a0dce83aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan, bz, bholley, smaug
bugs920015
milestone27.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 920015 - Expose DOM URL to js modules, r=ehsan, f=emk, r=bz, r=bholley, r=smaug
dom/base/URL.cpp
dom/base/URL.h
dom/base/test/chrome.ini
dom/base/test/file_url.jsm
dom/base/test/test_url.xul
dom/workers/URL.cpp
dom/workers/test/chrome.ini
dom/workers/test/file_url.jsm
dom/workers/test/test_url.xul
js/xpconnect/src/Sandbox.cpp
js/xpconnect/src/xpcprivate.h
js/xpconnect/tests/unit/test_url.js
js/xpconnect/tests/unit/xpcshell.ini
--- a/dom/base/URL.cpp
+++ b/dom/base/URL.cpp
@@ -15,72 +15,54 @@
 #include "nsIIOService.h"
 #include "nsEscape.h"
 #include "nsNetCID.h"
 #include "nsIURL.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_1(URL, mWindow)
-
-NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(URL, AddRef)
-NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(URL, Release)
-
-URL::URL(nsPIDOMWindow* aWindow, nsIURI* aURI)
-  : mWindow(aWindow)
-  , mURI(aURI)
+URL::URL(nsIURI* aURI)
+  : mURI(aURI)
 {
 }
 
 JSObject*
 URL::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return URLBinding::Wrap(aCx, aScope, this);
 }
 
 /* static */ already_AddRefed<URL>
 URL::Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
                  URL& aBase, ErrorResult& aRv)
 {
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
-  if (!window) {
-    aRv.Throw(NS_ERROR_UNEXPECTED);
-    return nullptr;
-  }
-
   nsresult rv;
   nsCOMPtr<nsIIOService> ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv));
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   nsCOMPtr<nsIURI> uri;
   rv = ioService->NewURI(NS_ConvertUTF16toUTF8(aUrl), nullptr, aBase.GetURI(),
                          getter_AddRefs(uri));
   if (NS_FAILED(rv)) {
     aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
     return nullptr;
   }
 
-  nsRefPtr<URL> url = new URL(window, uri);
+  nsRefPtr<URL> url = new URL(uri);
   return url.forget();
 }
 
 /* static */ already_AddRefed<URL>
 URL::Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
                   const nsAString& aBase, ErrorResult& aRv)
 {
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
-  if (!window) {
-    aRv.Throw(NS_ERROR_UNEXPECTED);
-    return nullptr;
-  }
-
   nsresult rv;
   nsCOMPtr<nsIIOService> ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv));
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   nsCOMPtr<nsIURI> baseUri;
@@ -94,108 +76,105 @@ URL::Constructor(const GlobalObject& aGl
   nsCOMPtr<nsIURI> uri;
   rv = ioService->NewURI(NS_ConvertUTF16toUTF8(aUrl), nullptr, baseUri,
                          getter_AddRefs(uri));
   if (NS_FAILED(rv)) {
     aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
     return nullptr;
   }
 
-  nsRefPtr<URL> url = new URL(window, uri);
+  nsRefPtr<URL> url = new URL(uri);
   return url.forget();
 }
 
 void
 URL::CreateObjectURL(const GlobalObject& aGlobal,
                      nsIDOMBlob* aBlob,
                      const objectURLOptions& aOptions,
                      nsString& aResult,
                      ErrorResult& aError)
 {
-  CreateObjectURLInternal(aGlobal.GetAsSupports(), aBlob,
+  CreateObjectURLInternal(aGlobal, aBlob,
                           NS_LITERAL_CSTRING(BLOBURI_SCHEME), aOptions, aResult,
                           aError);
 }
 
 void
 URL::CreateObjectURL(const GlobalObject& aGlobal, DOMMediaStream& aStream,
                      const mozilla::dom::objectURLOptions& aOptions,
                      nsString& aResult,
                      ErrorResult& aError)
 {
-  CreateObjectURLInternal(aGlobal.GetAsSupports(), &aStream,
+  CreateObjectURLInternal(aGlobal, &aStream,
                           NS_LITERAL_CSTRING(MEDIASTREAMURI_SCHEME), aOptions,
                           aResult, aError);
 }
 
 void
 URL::CreateObjectURL(const GlobalObject& aGlobal, MediaSource& aSource,
                      const objectURLOptions& aOptions,
                      nsString& aResult,
                      ErrorResult& aError)
 {
-  CreateObjectURLInternal(aGlobal.GetAsSupports(), &aSource,
+  CreateObjectURLInternal(aGlobal, &aSource,
                           NS_LITERAL_CSTRING(MEDIASOURCEURI_SCHEME), aOptions,
                           aResult, aError);
 }
 
 void
-URL::CreateObjectURLInternal(nsISupports* aGlobal, nsISupports* aObject,
+URL::CreateObjectURLInternal(const GlobalObject& aGlobal, nsISupports* aObject,
                              const nsACString& aScheme,
                              const objectURLOptions& aOptions,
                              nsString& aResult, ErrorResult& aError)
 {
-  nsCOMPtr<nsPIDOMWindow> w = do_QueryInterface(aGlobal);
-  nsGlobalWindow* window = static_cast<nsGlobalWindow*>(w.get());
-  NS_PRECONDITION(!window || window->IsInnerWindow(),
-                  "Should be inner window");
-
-  if (!window || !window->GetExtantDoc()) {
-    aError.Throw(NS_ERROR_INVALID_POINTER);
-    return;
-  }
-
-  nsIDocument* doc = window->GetExtantDoc();
+  nsCOMPtr<nsIPrincipal> principal = nsContentUtils::GetObjectPrincipal(aGlobal.Get());
 
   nsCString url;
   nsresult rv = nsHostObjectProtocolHandler::AddDataEntry(aScheme, aObject,
-    doc->NodePrincipal(), url);
+                                                          principal, url);
   if (NS_FAILED(rv)) {
     aError.Throw(rv);
     return;
   }
 
-  doc->RegisterHostObjectUri(url);
+  nsCOMPtr<nsPIDOMWindow> w = do_QueryInterface(aGlobal.GetAsSupports());
+  nsGlobalWindow* window = static_cast<nsGlobalWindow*>(w.get());
+
+  if (window) {
+    NS_PRECONDITION(window->IsInnerWindow(), "Should be inner window");
+
+    if (!window->GetExtantDoc()) {
+      aError.Throw(NS_ERROR_INVALID_POINTER);
+      return;
+    }
+
+    nsIDocument* doc = window->GetExtantDoc();
+    if (doc) {
+      doc->RegisterHostObjectUri(url);
+    }
+  }
+
   CopyASCIItoUTF16(url, aResult);
 }
 
 void
 URL::RevokeObjectURL(const GlobalObject& aGlobal, const nsAString& aURL)
 {
-  nsCOMPtr<nsPIDOMWindow> w = do_QueryInterface(aGlobal.GetAsSupports());
-  nsGlobalWindow* window = static_cast<nsGlobalWindow*>(w.get());
-  NS_PRECONDITION(!window || window->IsInnerWindow(),
-                  "Should be inner window");
-  if (!window)
-    return;
+  nsIPrincipal* principal = nsContentUtils::GetObjectPrincipal(aGlobal.Get());
 
   NS_LossyConvertUTF16toASCII asciiurl(aURL);
 
-  nsIPrincipal* winPrincipal = window->GetPrincipal();
-  if (!winPrincipal) {
-    return;
-  }
+  nsIPrincipal* urlPrincipal =
+    nsHostObjectProtocolHandler::GetDataEntryPrincipal(asciiurl);
 
-  nsIPrincipal* principal =
-    nsHostObjectProtocolHandler::GetDataEntryPrincipal(asciiurl);
-  bool subsumes;
-  if (principal && winPrincipal &&
-      NS_SUCCEEDED(winPrincipal->Subsumes(principal, &subsumes)) &&
-      subsumes) {
-    if (window->GetExtantDoc()) {
+  if (urlPrincipal && principal->Subsumes(urlPrincipal)) {
+    nsCOMPtr<nsPIDOMWindow> w = do_QueryInterface(aGlobal.GetAsSupports());
+    nsGlobalWindow* window = static_cast<nsGlobalWindow*>(w.get());
+
+    if (window && window->GetExtantDoc()) {
       window->GetExtantDoc()->UnregisterHostObjectUri(asciiurl);
     }
     nsHostObjectProtocolHandler::RemoveDataEntry(asciiurl);
   }
 }
 
 void
 URL::GetHref(nsString& aHref) const
--- a/dom/base/URL.h
+++ b/dom/base/URL.h
@@ -8,17 +8,16 @@
 #include "mozilla/dom/BindingDeclarations.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsAutoPtr.h"
 #include "nsString.h"
 
 class nsIDOMBlob;
 class nsISupports;
 class nsIURI;
-class nsPIDOMWindow;
 
 namespace mozilla {
 
 class ErrorResult;
 class DOMMediaStream;
 
 namespace dom {
 
@@ -28,25 +27,24 @@ struct objectURLOptions;
 
 namespace workers {
 class URLProxy;
 }
 
 class URL MOZ_FINAL
 {
 public:
-  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(URL)
-  NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(URL)
+  NS_INLINE_DECL_REFCOUNTING(URL)
 
-  URL(nsPIDOMWindow* aWindow, nsIURI* aURI);
+  URL(nsIURI* aURI);
 
   // WebIDL methods
-  nsPIDOMWindow* GetParentObject() const
+  nsISupports* GetParentObject() const
   {
-    return mWindow;
+    return nullptr;
   }
 
   JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope);
 
   static already_AddRefed<URL>
   Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
               URL& aBase, ErrorResult& aRv);
@@ -115,23 +113,23 @@ public:
   void SetHash(const nsAString& aArg);
 
 private:
   nsIURI* GetURI() const
   {
     return mURI;
   }
 
-  static void CreateObjectURLInternal(nsISupports* aGlobal, nsISupports* aObject,
+  static void CreateObjectURLInternal(const GlobalObject& aGlobal,
+                                      nsISupports* aObject,
                                       const nsACString& aScheme,
                                       const objectURLOptions& aOptions,
                                       nsString& aResult,
                                       ErrorResult& aError);
 
-  nsRefPtr<nsPIDOMWindow> mWindow;
   nsCOMPtr<nsIURI> mURI;
 
   friend class mozilla::dom::workers::URLProxy;
 };
 
 }
 }
 
--- a/dom/base/test/chrome.ini
+++ b/dom/base/test/chrome.ini
@@ -1,5 +1,8 @@
 [DEFAULT]
+support-files =
+  file_url.jsm
 
 [test_bug715041.xul]
 [test_bug715041_removal.xul]
 [test_domrequesthelper.xul]
+[test_url.xul]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/file_url.jsm
@@ -0,0 +1,18 @@
+this.EXPORTED_SYMBOLS = ['checkFromJSM'];
+
+this.checkFromJSM = function checkFromJSM(ok, is) {
+  Components.utils.importGlobalProperties(['URL']);
+
+  var url = new URL('http://www.example.com');
+  is(url.href, "http://www.example.com/", "JSM should have URL");
+
+  var url2 = new URL('/foobar', url);
+  is(url2.href, "http://www.example.com/foobar", "JSM should have URL - based on another URL");
+
+  var blob = new Blob(['a']);
+  var url = URL.createObjectURL(blob);
+  ok(url, "URL is created!");
+
+  URL.revokeObjectURL(url);
+  ok(true, "URL is revoked");
+}
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_url.xul
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+<window title="Test for URL API"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+  <!-- test results are displayed in the html:body -->
+  <body xmlns="http://www.w3.org/1999/xhtml">
+  </body>
+
+  <!-- test code goes here -->
+  <script type="application/javascript"><![CDATA[
+
+  /** Test for URL API. **/
+  const Cu = Components.utils;
+
+  // Import our test JSM. We first strip the filename off
+  // the chrome url, then append the jsm filename.
+  var base = /.*\//.exec(window.location.href)[0];
+  Cu.import(base + "file_url.jsm");
+
+  checkFromJSM(ok, is);
+
+  ]]></script>
+</window>
--- a/dom/workers/URL.cpp
+++ b/dom/workers/URL.cpp
@@ -330,17 +330,17 @@ public:
     nsCOMPtr<nsIURI> url;
     rv = ioService->NewURI(NS_ConvertUTF16toUTF8(mURL), nullptr, baseURL,
                            getter_AddRefs(url));
     if (NS_FAILED(rv)) {
       mRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
       return;
     }
 
-    mRetval = new URLProxy(new mozilla::dom::URL(nullptr, url));
+    mRetval = new URLProxy(new mozilla::dom::URL(url));
   }
 
   URLProxy*
   GetURLProxy()
   {
     return mRetval;
   }
 };
--- a/dom/workers/test/chrome.ini
+++ b/dom/workers/test/chrome.ini
@@ -12,16 +12,17 @@ support-files =
   fileReadSlice_worker.js
   fileReaderSyncErrors_worker.js
   fileReaderSync_worker.js
   fileSlice_worker.js
   fileSubWorker_worker.js
   file_worker.js
   jsm_url_worker.js
   workersDisabled_worker.js
+  file_url.jsm
 
 [test_bug883784.jsm]
 [test_bug883784.xul]
 [test_chromeWorker.xul]
 [test_chromeWorkerJSM.xul]
 [test_extension.xul]
 [test_extensionBootstrap.xul]
 [test_file.xul]
@@ -29,8 +30,9 @@ support-files =
 [test_fileBlobSubWorker.xul]
 [test_filePosting.xul]
 [test_fileReadSlice.xul]
 [test_fileReaderSync.xul]
 [test_fileReaderSyncErrors.xul]
 [test_fileSlice.xul]
 [test_fileSubWorker.xul]
 [test_workersDisabled.xul]
+[test_url.xul]
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/file_url.jsm
@@ -0,0 +1,23 @@
+this.EXPORTED_SYMBOLS = ['checkFromJSM'];
+
+this.checkFromJSM = function checkFromJSM(ok, is, finish) {
+  let worker = new ChromeWorker("jsm_url_worker.js");
+  worker.onmessage = function(event) {
+
+   if (event.data.type == 'finish') {
+     finish();
+    } else if (event.data.type == 'status') {
+      ok(event.data.status, event.data.msg);
+    }
+  }
+
+  var self = this;
+  worker.onerror = function(event) {
+    is(event.target, worker);
+    ok(false, "Worker had an error: " + event.data);
+    self.worker.terminate();
+    finish();
+  };
+
+  worker.postMessage(0);
+}
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/test_url.xul
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<window title="DOM Worker Threads Test"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        onload="test();">
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+  <script type="application/javascript" src="dom_worker_helper.js"/>
+
+  <script type="application/javascript">
+  <![CDATA[
+
+    function test()
+    {
+      waitForWorkerFinish();
+
+      Components.utils.import("chrome://mochitests/content/chrome/dom/workers/test/file_url.jsm");
+      checkFromJSM(ok, is, finish);
+    }
+
+  ]]>
+  </script>
+
+  <body xmlns="http://www.w3.org/1999/xhtml">
+    <p id="display"></p>
+    <div id="content" style="display:none;"></div>
+    <pre id="test"></pre>
+  </body>
+  <label id="test-result"/>
+</window>
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -28,16 +28,17 @@
 #include "xpcprivate.h"
 #include "XPCQuickStubs.h"
 #include "XPCWrapper.h"
 #include "XrayWrapper.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
 #include "mozilla/dom/TextDecoderBinding.h"
 #include "mozilla/dom/TextEncoderBinding.h"
+#include "mozilla/dom/URLBinding.h"
 
 using namespace mozilla;
 using namespace JS;
 using namespace js;
 using namespace xpc;
 
 using mozilla::dom::DestroyProtoAndIfaceCache;
 using mozilla::dom::indexedDB::IndexedDatabaseManager;
@@ -896,16 +897,18 @@ xpc::GlobalProperties::Parse(JSContext *
         if (!strcmp(name.ptr(), "indexedDB")) {
             indexedDB = true;
         } else if (!strcmp(name.ptr(), "XMLHttpRequest")) {
             XMLHttpRequest = true;
         } else if (!strcmp(name.ptr(), "TextEncoder")) {
             TextEncoder = true;
         } else if (!strcmp(name.ptr(), "TextDecoder")) {
             TextDecoder = true;
+        } else if (!strcmp(name.ptr(), "URL")) {
+            URL = true;
         } else if (!strcmp(name.ptr(), "atob")) {
             atob = true;
         } else if (!strcmp(name.ptr(), "btoa")) {
             btoa = true;
         } else {
             JS_ReportError(cx, "Unknown property name: %s", name.ptr());
             return false;
         }
@@ -928,16 +931,20 @@ xpc::GlobalProperties::Define(JSContext 
     if (TextEncoder &&
         !dom::TextEncoderBinding::GetConstructorObject(cx, obj))
         return false;
 
     if (TextDecoder &&
         !dom::TextDecoderBinding::GetConstructorObject(cx, obj))
         return false;
 
+    if (URL &&
+        !dom::URLBinding::GetConstructorObject(cx, obj))
+        return false;
+
     if (atob &&
         !JS_DefineFunction(cx, obj, "atob", Atob, 1, 0))
         return false;
 
     if (btoa &&
         !JS_DefineFunction(cx, obj, "btoa", Btoa, 1, 0))
         return false;
 
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -3585,22 +3585,23 @@ NewFunctionForwarder(JSContext *cx, JS::
 // Old fashioned xpc error reporter. Try to use JS_ReportError instead.
 nsresult
 ThrowAndFail(nsresult errNum, JSContext *cx, bool *retval);
 
 struct GlobalProperties {
     GlobalProperties() { mozilla::PodZero(this); }
     bool Parse(JSContext *cx, JS::HandleObject obj);
     bool Define(JSContext *cx, JS::HandleObject obj);
-    bool indexedDB;
-    bool XMLHttpRequest;
-    bool TextDecoder;
-    bool TextEncoder;
-    bool atob;
-    bool btoa;
+    bool indexedDB : 1;
+    bool XMLHttpRequest : 1;
+    bool TextDecoder : 1;
+    bool TextEncoder : 1;
+    bool URL : 1;
+    bool atob : 1;
+    bool btoa : 1;
 };
 
 // Infallible.
 already_AddRefed<nsIXPCComponents_utils_Sandbox>
 NewSandboxConstructor();
 
 // Returns true if class of 'obj' is SandboxClass.
 bool
copy from js/xpconnect/tests/unit/test_textDecoder.js
copy to js/xpconnect/tests/unit/test_url.js
--- a/js/xpconnect/tests/unit/test_textDecoder.js
+++ b/js/xpconnect/tests/unit/test_url.js
@@ -1,12 +1,10 @@
 function run_test() {
   var Cu = Components.utils;
-  sb = new Cu.Sandbox('http://www.example.com',
-                      { wantGlobalProperties: ["TextDecoder", "TextEncoder"] });
+  var sb = new Cu.Sandbox('http://www.example.com',
+                          { wantGlobalProperties: ["URL"] });
   sb.do_check_eq = do_check_eq;
-  Cu.evalInSandbox('do_check_eq(new TextDecoder().encoding, "utf-8");' +
-                   'do_check_eq(new TextEncoder().encoding, "utf-8");',
+  Cu.evalInSandbox('do_check_eq(new URL("http://www.example.com").host, "www.example.com");',
                    sb);
-  Cu.importGlobalProperties(["TextDecoder", "TextEncoder"]);
-  do_check_eq(new TextDecoder().encoding, "utf-8");
-  do_check_eq(new TextEncoder().encoding, "utf-8");
+  Cu.importGlobalProperties(["URL"]);
+  do_check_eq(new URL("http://www.example.com").host, "www.example.com");
 }
--- a/js/xpconnect/tests/unit/xpcshell.ini
+++ b/js/xpconnect/tests/unit/xpcshell.ini
@@ -64,16 +64,17 @@ fail-if = os == "android"
 [test_want_components.js]
 [test_components.js]
 [test_allowedDomains.js]
 [test_allowedDomainsXHR.js]
 [test_nuke_sandbox.js]
 [test_sandbox_metadata.js]
 [test_exportFunction.js]
 [test_textDecoder.js]
+[test_url.js]
 [test_sandbox_atob.js]
 [test_watchdog_enable.js]
 head = head_watchdog.js
 [test_watchdog_disable.js]
 head = head_watchdog.js
 [test_watchdog_toggle.js]
 head = head_watchdog.js
 [test_watchdog_default.js]