From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- dom/url/tests/browser.ini | 5 + dom/url/tests/browser_download_after_revoke.js | 94 +++++ dom/url/tests/chrome.ini | 12 + dom/url/tests/empty.html | 2 + dom/url/tests/file_url.jsm | 24 ++ dom/url/tests/file_worker_url.jsm | 23 ++ dom/url/tests/jsm_url_worker.js | 84 ++++ dom/url/tests/mochitest.ini | 25 ++ dom/url/tests/protocol_worker.js | 25 ++ dom/url/tests/test_bloburl_location.html | 35 ++ dom/url/tests/test_bug883784.jsm | 38 ++ dom/url/tests/test_bug883784.xhtml | 34 ++ dom/url/tests/test_unknown_url_origin.html | 17 + dom/url/tests/test_url.html | 507 ++++++++++++++++++++++++ dom/url/tests/test_url.xhtml | 24 ++ dom/url/tests/test_urlExceptions.html | 56 +++ dom/url/tests/test_urlSearchParams.html | 59 +++ dom/url/tests/test_urlSearchParams_sorting.html | 63 +++ dom/url/tests/test_urlSearchParams_utf8.html | 39 ++ dom/url/tests/test_url_data.html | 45 +++ dom/url/tests/test_url_empty_port.html | 53 +++ dom/url/tests/test_url_malformedHost.html | 48 +++ dom/url/tests/test_urlutils_stringify.html | 38 ++ dom/url/tests/test_worker_protocol.html | 41 ++ dom/url/tests/test_worker_url.html | 66 +++ dom/url/tests/test_worker_url.xhtml | 33 ++ dom/url/tests/test_worker_urlApi.html | 43 ++ dom/url/tests/test_worker_urlSearchParams.html | 43 ++ dom/url/tests/test_worker_url_exceptions.html | 42 ++ dom/url/tests/urlApi_worker.js | 354 +++++++++++++++++ dom/url/tests/urlSearchParams_commons.js | 376 ++++++++++++++++++ dom/url/tests/urlSearchParams_worker.js | 48 +++ dom/url/tests/url_exceptions_worker.js | 38 ++ dom/url/tests/url_worker.js | 98 +++++ 34 files changed, 2532 insertions(+) create mode 100644 dom/url/tests/browser.ini create mode 100644 dom/url/tests/browser_download_after_revoke.js create mode 100644 dom/url/tests/chrome.ini create mode 100644 dom/url/tests/empty.html create mode 100644 dom/url/tests/file_url.jsm create mode 100644 dom/url/tests/file_worker_url.jsm create mode 100644 dom/url/tests/jsm_url_worker.js create mode 100644 dom/url/tests/mochitest.ini create mode 100644 dom/url/tests/protocol_worker.js create mode 100644 dom/url/tests/test_bloburl_location.html create mode 100644 dom/url/tests/test_bug883784.jsm create mode 100644 dom/url/tests/test_bug883784.xhtml create mode 100644 dom/url/tests/test_unknown_url_origin.html create mode 100644 dom/url/tests/test_url.html create mode 100644 dom/url/tests/test_url.xhtml create mode 100644 dom/url/tests/test_urlExceptions.html create mode 100644 dom/url/tests/test_urlSearchParams.html create mode 100644 dom/url/tests/test_urlSearchParams_sorting.html create mode 100644 dom/url/tests/test_urlSearchParams_utf8.html create mode 100644 dom/url/tests/test_url_data.html create mode 100644 dom/url/tests/test_url_empty_port.html create mode 100644 dom/url/tests/test_url_malformedHost.html create mode 100644 dom/url/tests/test_urlutils_stringify.html create mode 100644 dom/url/tests/test_worker_protocol.html create mode 100644 dom/url/tests/test_worker_url.html create mode 100644 dom/url/tests/test_worker_url.xhtml create mode 100644 dom/url/tests/test_worker_urlApi.html create mode 100644 dom/url/tests/test_worker_urlSearchParams.html create mode 100644 dom/url/tests/test_worker_url_exceptions.html create mode 100644 dom/url/tests/urlApi_worker.js create mode 100644 dom/url/tests/urlSearchParams_commons.js create mode 100644 dom/url/tests/urlSearchParams_worker.js create mode 100644 dom/url/tests/url_exceptions_worker.js create mode 100644 dom/url/tests/url_worker.js (limited to 'dom/url/tests') diff --git a/dom/url/tests/browser.ini b/dom/url/tests/browser.ini new file mode 100644 index 0000000000..ad58be9034 --- /dev/null +++ b/dom/url/tests/browser.ini @@ -0,0 +1,5 @@ +[DEFAULT] +support-files = + empty.html + +[browser_download_after_revoke.js] diff --git a/dom/url/tests/browser_download_after_revoke.js b/dom/url/tests/browser_download_after_revoke.js new file mode 100644 index 0000000000..be8ad96e70 --- /dev/null +++ b/dom/url/tests/browser_download_after_revoke.js @@ -0,0 +1,94 @@ +async function test() { + waitForExplicitFinish(); + const target = "http://example.com/browser/dom/url/tests/empty.html"; + info("Loading download page..."); + let tab = BrowserTestUtils.addTab(gBrowser, target); + registerCleanupFunction(function () { + gBrowser.removeTab(tab); + window.restore(); + }); + gBrowser.selectedTab = tab; + BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, target).then( + async () => { + info("Page loaded."); + let allDownloads = await Downloads.getList(Downloads.ALL); + let started = new Promise(resolve => { + if ( + Services.prefs.getBoolPref( + "browser.download.always_ask_before_handling_new_types", + false + ) + ) { + // If the download modal is enabled, wait for it to open and declare the + // download to have begun when we see it. + let listener = { + onOpenWindow(aXULWindow) { + info("Download modal shown..."); + Services.wm.removeListener(listener); + + let domwindow = aXULWindow.docShell.domWindow; + function onModalLoad() { + domwindow.removeEventListener("load", onModalLoad, true); + + is( + domwindow.document.location.href, + "chrome://mozapps/content/downloads/unknownContentType.xhtml", + "Download modal loaded..." + ); + + domwindow.close(); + info("Download modal closed."); + resolve(); + } + + domwindow.addEventListener("load", onModalLoad, true); + }, + onCloseWindow(aXULWindow) {}, + }; + + Services.wm.addListener(listener); + } else { + // With no download modal, the download will begin on its own, so we need + // to wait to be notified by the downloads list when that happens. + let downloadView = { + onDownloadAdded(download) { + ok(true, "Download was started."); + download.cancel(); + allDownloads.removeView(this); + allDownloads.removeFinished(); + resolve(); + }, + }; + allDownloads.addView(downloadView); + } + }); + + let revoked = SpecialPowers.spawn( + tab.linkedBrowser, + [], + () => + new Promise(resolve => { + info("Creating BlobURL..."); + let blob = new content.Blob(["test"], { type: "text/plain" }); + let url = content.URL.createObjectURL(blob); + + let link = content.document.createElement("a"); + link.href = url; + link.download = "example.txt"; + content.document.body.appendChild(link); + info("Clicking HTMLAnchorElement..."); + link.click(); + + content.URL.revokeObjectURL(url); + info("BlobURL revoked."); + resolve(); + }) + ); + + info("Waiting for async activities..."); + await Promise.all([revoked, started]); + ok(true, "Exiting test."); + finish(); + } + ); +} diff --git a/dom/url/tests/chrome.ini b/dom/url/tests/chrome.ini new file mode 100644 index 0000000000..1f1b9022c9 --- /dev/null +++ b/dom/url/tests/chrome.ini @@ -0,0 +1,12 @@ +[DEFAULT] +skip-if = os == 'android' +support-files = + file_url.jsm + file_worker_url.jsm + test_bug883784.jsm + jsm_url_worker.js + !/dom/workers/test/dom_worker_helper.js + +[test_bug883784.xhtml] +[test_url.xhtml] +[test_worker_url.xhtml] diff --git a/dom/url/tests/empty.html b/dom/url/tests/empty.html new file mode 100644 index 0000000000..358db717dd --- /dev/null +++ b/dom/url/tests/empty.html @@ -0,0 +1,2 @@ + + diff --git a/dom/url/tests/file_url.jsm b/dom/url/tests/file_url.jsm new file mode 100644 index 0000000000..6be99f2931 --- /dev/null +++ b/dom/url/tests/file_url.jsm @@ -0,0 +1,24 @@ +var EXPORTED_SYMBOLS = ["checkFromJSM"]; + +function checkFromJSM(ok, is) { + 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"]); + url = URL.createObjectURL(blob); + ok(url, "URL is created!"); + + var u = new URL(url); + ok(u, "URL created"); + is(u.origin, "null", "Url doesn't have an origin if created in a JSM"); + + URL.revokeObjectURL(url); + ok(true, "URL is revoked"); +} diff --git a/dom/url/tests/file_worker_url.jsm b/dom/url/tests/file_worker_url.jsm new file mode 100644 index 0000000000..30a072ef9d --- /dev/null +++ b/dom/url/tests/file_worker_url.jsm @@ -0,0 +1,23 @@ +var EXPORTED_SYMBOLS = ["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 == "url") { + URL.revokeObjectURL(event.data.url); + } else if (event.data.type == "status") { + ok(event.data.status, event.data.msg); + } + }; + + worker.onerror = function (event) { + is(event.target, worker); + ok(false, "Worker had an error: " + event.data); + worker.terminate(); + finish(); + }; + + worker.postMessage(0); +} diff --git a/dom/url/tests/jsm_url_worker.js b/dom/url/tests/jsm_url_worker.js new file mode 100644 index 0000000000..d4cabe4113 --- /dev/null +++ b/dom/url/tests/jsm_url_worker.js @@ -0,0 +1,84 @@ +/* eslint-env worker */ + +onmessage = function (event) { + if (event.data != 0) { + var worker = new Worker("jsm_url_worker.js"); + worker.onmessage = function (ev) { + postMessage(ev.data); + }; + + worker.postMessage(event.data - 1); + return; + } + + let status = false; + try { + if (URL instanceof Object) { + status = true; + } + } catch (e) {} + + postMessage({ type: "status", status, msg: "URL object:" + URL }); + + status = false; + var blob = null; + try { + blob = new Blob([]); + status = true; + } catch (e) {} + + postMessage({ type: "status", status, msg: "Blob:" + blob }); + + status = false; + var url = null; + try { + url = URL.createObjectURL(blob); + status = true; + } catch (e) {} + + postMessage({ type: "status", status, msg: "Blob URL:" + url }); + + status = false; + try { + URL.revokeObjectURL(url); + status = true; + } catch (e) {} + + postMessage({ type: "status", status, msg: "Blob Revoke URL" }); + + status = false; + url = null; + try { + url = URL.createObjectURL(true); + } catch (e) { + status = true; + } + + postMessage({ + type: "status", + status, + msg: "CreateObjectURL should fail if the arg is not a blob", + }); + + status = false; + url = null; + try { + url = URL.createObjectURL(blob); + status = true; + } catch (e) {} + + postMessage({ type: "status", status, msg: "Blob URL2:" + url }); + + status = false; + try { + URL.createObjectURL({}); + } catch (e) { + status = true; + } + + postMessage({ type: "status", status, msg: "Exception wanted" }); + + postMessage({ type: "url", url }); + + postMessage({ type: "finish" }); +}; diff --git a/dom/url/tests/mochitest.ini b/dom/url/tests/mochitest.ini new file mode 100644 index 0000000000..0e14b90ea9 --- /dev/null +++ b/dom/url/tests/mochitest.ini @@ -0,0 +1,25 @@ +[DEFAULT] +support-files = + url_worker.js + urlApi_worker.js + urlSearchParams_commons.js + urlSearchParams_worker.js + url_exceptions_worker.js + +[test_url.html] +[test_url_data.html] +[test_url_empty_port.html] +[test_url_malformedHost.html] +[test_urlExceptions.html] +[test_urlSearchParams.html] +[test_urlSearchParams_sorting.html] +[test_urlSearchParams_utf8.html] +[test_urlutils_stringify.html] +[test_worker_url.html] +[test_worker_urlApi.html] +[test_worker_url_exceptions.html] +[test_worker_urlSearchParams.html] +[test_unknown_url_origin.html] +[test_bloburl_location.html] +[test_worker_protocol.html] +support-files = protocol_worker.js diff --git a/dom/url/tests/protocol_worker.js b/dom/url/tests/protocol_worker.js new file mode 100644 index 0000000000..c038254a4c --- /dev/null +++ b/dom/url/tests/protocol_worker.js @@ -0,0 +1,25 @@ +function ok(a, msg) { + postMessage({ type: "status", status: !!a, msg }); +} + +function is(a, b, msg) { + ok(a === b, msg); +} + +function finish() { + postMessage({ type: "finish" }); +} + +let url = new URL("http://example.com"); +is(url.protocol, "http:", "http: expected"); + +url.protocol = "https:"; +is(url.protocol, "https:", "http: -> https:"); + +url.protocol = "ftp:"; +is(url.protocol, "ftp:", "https: -> ftp:"); + +url.protocol = "https:"; +is(url.protocol, "https:", "ftp: -> https:"); + +finish(); diff --git a/dom/url/tests/test_bloburl_location.html b/dom/url/tests/test_bloburl_location.html new file mode 100644 index 0000000000..f8442cffc5 --- /dev/null +++ b/dom/url/tests/test_bloburl_location.html @@ -0,0 +1,35 @@ + + + + + Test for blobURL in location + + + + + + + diff --git a/dom/url/tests/test_bug883784.jsm b/dom/url/tests/test_bug883784.jsm new file mode 100644 index 0000000000..1790007680 --- /dev/null +++ b/dom/url/tests/test_bug883784.jsm @@ -0,0 +1,38 @@ +var EXPORTED_SYMBOLS = ["Test"]; + +var Test = { + start(ok, is, finish) { + let worker = new ChromeWorker("jsm_url_worker.js"); + worker.onmessage = function (event) { + if (event.data.type == "status") { + ok(event.data.status, event.data.msg); + } else if (event.data.type == "url") { + var xhr = new XMLHttpRequest(); + xhr.open("GET", event.data.url, false); + xhr.onreadystatechange = function () { + if (xhr.readyState == 4) { + ok(true, "Blob readable!"); + URL.revokeObjectURL(event.data.url); + finish(); + } + }; + xhr.onerror = function () { + ok(false, "Blob unreadable, should not happen!"); + URL.revokeObjectURL(event.data.url); + finish(); + }; + xhr.send(); + } + }; + + 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); + }, +}; diff --git a/dom/url/tests/test_bug883784.xhtml b/dom/url/tests/test_bug883784.xhtml new file mode 100644 index 0000000000..381eb08a37 --- /dev/null +++ b/dom/url/tests/test_bug883784.xhtml @@ -0,0 +1,34 @@ + + + + + + + +

+ +

+  
+  
diff --git a/dom/url/tests/test_unknown_url_origin.html b/dom/url/tests/test_unknown_url_origin.html new file mode 100644 index 0000000000..1c5571e9e4 --- /dev/null +++ b/dom/url/tests/test_unknown_url_origin.html @@ -0,0 +1,17 @@ + + + + + Test for unknwon URL.origin + + + + + + + diff --git a/dom/url/tests/test_url.html b/dom/url/tests/test_url.html new file mode 100644 index 0000000000..85f39e54b9 --- /dev/null +++ b/dom/url/tests/test_url.html @@ -0,0 +1,507 @@ + + + + + Test URL API + + + + +Mozilla Bug 887364 +Mozilla Bug 991471 +Mozilla Bug 996055 +

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dom/url/tests/test_url.xhtml b/dom/url/tests/test_url.xhtml new file mode 100644 index 0000000000..10978c1f72 --- /dev/null +++ b/dom/url/tests/test_url.xhtml @@ -0,0 +1,24 @@ + + + + + + diff --git a/dom/url/tests/test_urlExceptions.html b/dom/url/tests/test_urlExceptions.html new file mode 100644 index 0000000000..4feb30a948 --- /dev/null +++ b/dom/url/tests/test_urlExceptions.html @@ -0,0 +1,56 @@ + + + + + + Test for Bug 926890 + + + + +Mozilla Bug 926890 +

+ +
+
+ + + diff --git a/dom/url/tests/test_urlSearchParams.html b/dom/url/tests/test_urlSearchParams.html new file mode 100644 index 0000000000..d86959ab64 --- /dev/null +++ b/dom/url/tests/test_urlSearchParams.html @@ -0,0 +1,59 @@ + + + + + + + Test for URLSearchParams + + + + + +Mozilla Bug 887836 +

+ +
+
+ + + diff --git a/dom/url/tests/test_urlSearchParams_sorting.html b/dom/url/tests/test_urlSearchParams_sorting.html new file mode 100644 index 0000000000..a608e8bc13 --- /dev/null +++ b/dom/url/tests/test_urlSearchParams_sorting.html @@ -0,0 +1,63 @@ + + + + + + Test for URLSearchParams.sort() + + + + + + + diff --git a/dom/url/tests/test_urlSearchParams_utf8.html b/dom/url/tests/test_urlSearchParams_utf8.html new file mode 100644 index 0000000000..2a37b3b9a1 --- /dev/null +++ b/dom/url/tests/test_urlSearchParams_utf8.html @@ -0,0 +1,39 @@ + + + + + + + Test for Bug 1032511 + + + + +Mozilla Bug 1032511 +

+ +
+
+foobar +foobar + + + diff --git a/dom/url/tests/test_url_data.html b/dom/url/tests/test_url_data.html new file mode 100644 index 0000000000..a4d017936a --- /dev/null +++ b/dom/url/tests/test_url_data.html @@ -0,0 +1,45 @@ + + + + + Test URL API - data:plain + + + + +Mozilla Bug 1018682 + + + + + diff --git a/dom/url/tests/test_url_empty_port.html b/dom/url/tests/test_url_empty_port.html new file mode 100644 index 0000000000..5001bdfae5 --- /dev/null +++ b/dom/url/tests/test_url_empty_port.html @@ -0,0 +1,53 @@ + + + + + + + Test for Bug 930450 + + + + +Mozilla Bug 930450 +

+ +
+
+ foobar + + + + diff --git a/dom/url/tests/test_url_malformedHost.html b/dom/url/tests/test_url_malformedHost.html new file mode 100644 index 0000000000..7cc23d7e32 --- /dev/null +++ b/dom/url/tests/test_url_malformedHost.html @@ -0,0 +1,48 @@ + + + + + + + Test for Bug 1020041 + + + + +Mozilla Bug 1020041 +

+ +
+
+ foobar + + + + diff --git a/dom/url/tests/test_urlutils_stringify.html b/dom/url/tests/test_urlutils_stringify.html new file mode 100644 index 0000000000..7c68051535 --- /dev/null +++ b/dom/url/tests/test_urlutils_stringify.html @@ -0,0 +1,38 @@ + + + + + + + Test for Bug 959190 + + + + +Mozilla Bug 959190 +

+ +
+
+ foobar + + + + diff --git a/dom/url/tests/test_worker_protocol.html b/dom/url/tests/test_worker_protocol.html new file mode 100644 index 0000000000..1687159d6a --- /dev/null +++ b/dom/url/tests/test_worker_protocol.html @@ -0,0 +1,41 @@ + + + + + Test for URL protocol setter in workers + + + + +

+ +

+
+
+
+
diff --git a/dom/url/tests/test_worker_url.html b/dom/url/tests/test_worker_url.html
new file mode 100644
index 0000000000..8bcd265d19
--- /dev/null
+++ b/dom/url/tests/test_worker_url.html
@@ -0,0 +1,66 @@
+
+
+
+
+  Test for URL object in workers
+  
+  
+
+
+

+ +

+
+
+
+
diff --git a/dom/url/tests/test_worker_url.xhtml b/dom/url/tests/test_worker_url.xhtml
new file mode 100644
index 0000000000..30d2aa131d
--- /dev/null
+++ b/dom/url/tests/test_worker_url.xhtml
@@ -0,0 +1,33 @@
+
+
+
+
+  
+
+  
+    

+ +

+  
+  
diff --git a/dom/url/tests/test_worker_urlApi.html b/dom/url/tests/test_worker_urlApi.html new file mode 100644 index 0000000000..34de982ef1 --- /dev/null +++ b/dom/url/tests/test_worker_urlApi.html @@ -0,0 +1,43 @@ + + + + + Test for URL API object in workers + + + + +

+ +

+
+
+
+
diff --git a/dom/url/tests/test_worker_urlSearchParams.html b/dom/url/tests/test_worker_urlSearchParams.html
new file mode 100644
index 0000000000..1870d5d7dc
--- /dev/null
+++ b/dom/url/tests/test_worker_urlSearchParams.html
@@ -0,0 +1,43 @@
+
+
+
+
+  Test for URLSearchParams object in workers
+  
+  
+
+
+

+ +

+
+
+
+
diff --git a/dom/url/tests/test_worker_url_exceptions.html b/dom/url/tests/test_worker_url_exceptions.html
new file mode 100644
index 0000000000..2c8b493bbf
--- /dev/null
+++ b/dom/url/tests/test_worker_url_exceptions.html
@@ -0,0 +1,42 @@
+
+
+
+
+  Test for URL exceptions in workers
+  
+  
+
+
+

+ +

+
+
+
+
diff --git a/dom/url/tests/urlApi_worker.js b/dom/url/tests/urlApi_worker.js
new file mode 100644
index 0000000000..40243c1e66
--- /dev/null
+++ b/dom/url/tests/urlApi_worker.js
@@ -0,0 +1,354 @@
+/* eslint-env worker */
+
+function ok(a, msg) {
+  dump("OK: " + !!a + "  =>  " + a + " " + msg + "\n");
+  postMessage({ type: "status", status: !!a, msg: a + ": " + msg });
+}
+
+function is(a, b, msg) {
+  dump("IS: " + (a === b) + "  =>  " + a + " | " + b + " " + msg + "\n");
+  postMessage({
+    type: "status",
+    status: a === b,
+    msg: a + " === " + b + ": " + msg,
+  });
+}
+
+// eslint-disable-next-line complexity
+onmessage = function () {
+  let status = false;
+  try {
+    if (URL instanceof Object) {
+      status = true;
+    }
+  } catch (e) {}
+
+  ok(status, "URL in workers \\o/");
+
+  var tests = [
+    {
+      url: "http://www.abc.com",
+      base: undefined,
+      error: false,
+      href: "http://www.abc.com/",
+      origin: "http://www.abc.com",
+      protocol: "http:",
+      username: "",
+      password: "",
+      host: "www.abc.com",
+      hostname: "www.abc.com",
+      port: "",
+      pathname: "/",
+      search: "",
+      hash: "",
+    },
+    {
+      url: "ftp://auser:apw@www.abc.com",
+      base: undefined,
+      error: false,
+      href: "ftp://auser:apw@www.abc.com/",
+      origin: "ftp://www.abc.com",
+      protocol: "ftp:",
+      username: "auser",
+      password: "apw",
+      host: "www.abc.com",
+      hostname: "www.abc.com",
+      port: "",
+      pathname: "/",
+      search: "",
+      hash: "",
+    },
+    {
+      url: "http://www.abc.com:90/apath/",
+      base: undefined,
+      error: false,
+      href: "http://www.abc.com:90/apath/",
+      origin: "http://www.abc.com:90",
+      protocol: "http:",
+      username: "",
+      password: "",
+      host: "www.abc.com:90",
+      hostname: "www.abc.com",
+      port: "90",
+      pathname: "/apath/",
+      search: "",
+      hash: "",
+    },
+    {
+      url: "http://www.abc.com/apath/afile.txt#ahash",
+      base: undefined,
+      error: false,
+      href: "http://www.abc.com/apath/afile.txt#ahash",
+      origin: "http://www.abc.com",
+      protocol: "http:",
+      username: "",
+      password: "",
+      host: "www.abc.com",
+      hostname: "www.abc.com",
+      port: "",
+      pathname: "/apath/afile.txt",
+      search: "",
+      hash: "#ahash",
+    },
+    {
+      url: "http://example.com/?test#hash",
+      base: undefined,
+      error: false,
+      href: "http://example.com/?test#hash",
+      origin: "http://example.com",
+      protocol: "http:",
+      username: "",
+      password: "",
+      host: "example.com",
+      hostname: "example.com",
+      port: "",
+      pathname: "/",
+      search: "?test",
+      hash: "#hash",
+    },
+    {
+      url: "http://example.com/?test",
+      base: undefined,
+      error: false,
+      href: "http://example.com/?test",
+      origin: "http://example.com",
+      protocol: "http:",
+      username: "",
+      password: "",
+      host: "example.com",
+      hostname: "example.com",
+      port: "",
+      pathname: "/",
+      search: "?test",
+      hash: "",
+    },
+    {
+      url: "http://example.com/carrot#question%3f",
+      base: undefined,
+      error: false,
+      hash: "#question%3f",
+    },
+    {
+      url: "https://example.com:4443?",
+      base: undefined,
+      error: false,
+      protocol: "https:",
+      port: "4443",
+      pathname: "/",
+      hash: "",
+      search: "",
+    },
+    {
+      url: "http://www.abc.com/apath/afile.txt#ahash?asearch",
+      base: undefined,
+      error: false,
+      href: "http://www.abc.com/apath/afile.txt#ahash?asearch",
+      protocol: "http:",
+      pathname: "/apath/afile.txt",
+      hash: "#ahash?asearch",
+      search: "",
+    },
+    {
+      url: "http://www.abc.com/apath/afile.txt?asearch#ahash",
+      base: undefined,
+      error: false,
+      href: "http://www.abc.com/apath/afile.txt?asearch#ahash",
+      protocol: "http:",
+      pathname: "/apath/afile.txt",
+      hash: "#ahash",
+      search: "?asearch",
+    },
+    {
+      url: "http://abc.com/apath/afile.txt?#ahash",
+      base: undefined,
+      error: false,
+      pathname: "/apath/afile.txt",
+      hash: "#ahash",
+      search: "",
+    },
+    {
+      url: "http://auser:apassword@www.abc.com:90/apath/afile.txt?asearch#ahash",
+      base: undefined,
+      error: false,
+      protocol: "http:",
+      username: "auser",
+      password: "apassword",
+      host: "www.abc.com:90",
+      hostname: "www.abc.com",
+      port: "90",
+      pathname: "/apath/afile.txt",
+      hash: "#ahash",
+      search: "?asearch",
+      origin: "http://www.abc.com:90",
+    },
+
+    { url: "/foo#bar", base: "www.test.org", error: true },
+    { url: "/foo#bar", base: null, error: true },
+    { url: "/foo#bar", base: 42, error: true },
+    {
+      url: "ftp://ftp.something.net",
+      base: undefined,
+      error: false,
+      protocol: "ftp:",
+    },
+    {
+      url: "file:///tmp/file",
+      base: undefined,
+      error: false,
+      protocol: "file:",
+    },
+    {
+      url: "gopher://gopher.something.net",
+      base: undefined,
+      error: false,
+      protocol: "gopher:",
+    },
+    {
+      url: "ws://ws.something.net",
+      base: undefined,
+      error: false,
+      protocol: "ws:",
+    },
+    {
+      url: "wss://ws.something.net",
+      base: undefined,
+      error: false,
+      protocol: "wss:",
+    },
+    {
+      url: "foo://foo.something.net",
+      base: undefined,
+      error: false,
+      protocol: "foo:",
+    },
+  ];
+
+  while (tests.length) {
+    var test = tests.shift();
+
+    var error = false;
+    var url;
+    try {
+      if (test.base) {
+        url = new URL(test.url, test.base);
+      } else {
+        url = new URL(test.url);
+      }
+    } catch (e) {
+      error = true;
+    }
+
+    is(test.error, error, "Error creating URL");
+    if (test.error) {
+      continue;
+    }
+
+    if ("href" in test) {
+      is(url.href, test.href, "href");
+    }
+    if ("origin" in test) {
+      is(url.origin, test.origin, "origin");
+    }
+    if ("protocol" in test) {
+      is(url.protocol, test.protocol, "protocol");
+    }
+    if ("username" in test) {
+      is(url.username, test.username, "username");
+    }
+    if ("password" in test) {
+      is(url.password, test.password, "password");
+    }
+    if ("host" in test) {
+      is(url.host, test.host, "host");
+    }
+    if ("hostname" in test) {
+      is(url.hostname, test.hostname, "hostname");
+    }
+    if ("port" in test) {
+      is(url.port, test.port, "port");
+    }
+    if ("pathname" in test) {
+      is(url.pathname, test.pathname, "pathname");
+    }
+    if ("search" in test) {
+      is(url.search, test.search, "search");
+    }
+    if ("hash" in test) {
+      is(url.hash, test.hash, "hash");
+    }
+
+    url = new URL("https://www.example.net/what#foo?bar");
+    ok(url, "Url exists!");
+
+    if ("href" in test) {
+      url.href = test.href;
+    }
+    if ("protocol" in test) {
+      url.protocol = test.protocol;
+    }
+    if ("username" in test && test.username) {
+      url.username = test.username;
+    }
+    if ("password" in test && test.password) {
+      url.password = test.password;
+    }
+    if ("host" in test) {
+      url.host = test.host;
+    }
+    if ("hostname" in test) {
+      url.hostname = test.hostname;
+    }
+    if ("port" in test) {
+      url.port = test.port;
+    }
+    if ("pathname" in test) {
+      url.pathname = test.pathname;
+    }
+    if ("search" in test) {
+      url.search = test.search;
+    }
+    if ("hash" in test) {
+      url.hash = test.hash;
+    }
+
+    if ("href" in test) {
+      is(url.href, test.href, "href");
+    }
+    if ("origin" in test) {
+      is(url.origin, test.origin, "origin");
+    }
+    if ("protocol" in test) {
+      is(url.protocol, test.protocol, "protocol");
+    }
+    if ("username" in test) {
+      is(url.username, test.username, "username");
+    }
+    if ("password" in test) {
+      is(url.password, test.password, "password");
+    }
+    if ("host" in test) {
+      is(url.host, test.host, "host");
+    }
+    if ("hostname" in test) {
+      is(test.hostname, url.hostname, "hostname");
+    }
+    if ("port" in test) {
+      is(test.port, url.port, "port");
+    }
+    if ("pathname" in test) {
+      is(test.pathname, url.pathname, "pathname");
+    }
+    if ("search" in test) {
+      is(test.search, url.search, "search");
+    }
+    if ("hash" in test) {
+      is(test.hash, url.hash, "hash");
+    }
+
+    if ("href" in test) {
+      is(test.href, url + "", "stringify works");
+    }
+  }
+
+  postMessage({ type: "finish" });
+};
diff --git a/dom/url/tests/urlSearchParams_commons.js b/dom/url/tests/urlSearchParams_commons.js
new file mode 100644
index 0000000000..3a1dcb2807
--- /dev/null
+++ b/dom/url/tests/urlSearchParams_commons.js
@@ -0,0 +1,376 @@
+/* import-globals-from urlSearchParams_worker.js */
+
+function testSimpleURLSearchParams() {
+  var u = new URLSearchParams();
+  ok(u, "URLSearchParams created");
+  is(u.has("foo"), false, "URLSearchParams.has(foo)");
+  is(u.get("foo"), null, "URLSearchParams.get(foo)");
+  is(u.getAll("foo").length, 0, "URLSearchParams.getAll(foo)");
+
+  u.append("foo", "bar");
+  is(u.has("foo"), true, "URLSearchParams.has(foo)");
+  is(u.get("foo"), "bar", "URLSearchParams.get(foo)");
+  is(u.getAll("foo").length, 1, "URLSearchParams.getAll(foo)");
+
+  u.set("foo", "bar2");
+  is(u.get("foo"), "bar2", "URLSearchParams.get(foo)");
+  is(u.getAll("foo").length, 1, "URLSearchParams.getAll(foo)");
+
+  is(u + "", "foo=bar2", "stringifier");
+
+  u.delete("foo");
+
+  runTest();
+}
+
+function testCopyURLSearchParams() {
+  var u = new URLSearchParams();
+  ok(u, "URLSearchParams created");
+  u.append("foo", "bar");
+
+  var uu = new URLSearchParams(u);
+  is(uu.get("foo"), "bar", "uu.get()");
+
+  u.append("foo", "bar2");
+  is(u.getAll("foo").length, 2, "u.getAll()");
+  is(uu.getAll("foo").length, 1, "uu.getAll()");
+
+  runTest();
+}
+
+function testURL() {
+  var url = new URL("http://www.example.net?a=b&c=d");
+  ok(url.searchParams, "URL searchParams exists!");
+  ok(url.searchParams.has("a"), "URL.searchParams.has('a')");
+  is(url.searchParams.get("a"), "b", "URL.searchParams.get('a')");
+  ok(url.searchParams.has("c"), "URL.searchParams.has('c')");
+  is(url.searchParams.get("c"), "d", "URL.searchParams.get('c')");
+
+  url.searchParams.set("e", "f");
+  ok(url.href.indexOf("e=f") != 1, "URL right");
+
+  url = new URL("mailto:a@b.com?subject=Hi");
+  ok(url.searchParams, "URL searchParams exists!");
+  ok(url.searchParams.has("subject"), "Hi");
+
+  runTest();
+}
+
+function testParserURLSearchParams() {
+  var checks = [
+    { input: "", data: {} },
+    { input: "a", data: { a: [""] } },
+    { input: "a=b", data: { a: ["b"] } },
+    { input: "a=", data: { a: [""] } },
+    { input: "=b", data: { "": ["b"] } },
+    { input: "&", data: {} },
+    { input: "&a", data: { a: [""] } },
+    { input: "a&", data: { a: [""] } },
+    { input: "a&a", data: { a: ["", ""] } },
+    { input: "a&b&c", data: { a: [""], b: [""], c: [""] } },
+    { input: "a=b&c=d", data: { a: ["b"], c: ["d"] } },
+    { input: "a=b&c=d&", data: { a: ["b"], c: ["d"] } },
+    { input: "&&&a=b&&&&c=d&", data: { a: ["b"], c: ["d"] } },
+    { input: "a=a&a=b&a=c", data: { a: ["a", "b", "c"] } },
+    { input: "a==a", data: { a: ["=a"] } },
+    { input: "a=a+b+c+d", data: { a: ["a b c d"] } },
+    { input: "%=a", data: { "%": ["a"] } },
+    { input: "%a=a", data: { "%a": ["a"] } },
+    { input: "%a_=a", data: { "%a_": ["a"] } },
+    { input: "%61=a", data: { a: ["a"] } },
+    { input: "%=a", data: { "%": ["a"] } },
+    { input: "%a=a", data: { "%a": ["a"] } },
+    { input: "%a_=a", data: { "%a_": ["a"] } },
+    { input: "%61=a", data: { a: ["a"] } },
+    { input: "%61+%4d%4D=", data: { "a MM": [""] } },
+    { input: "?a=1", data: { a: ["1"] } },
+    { input: "?", data: {} },
+    { input: "?=b", data: { "": ["b"] } },
+  ];
+
+  for (var i = 0; i < checks.length; ++i) {
+    var u = new URLSearchParams(checks[i].input);
+
+    var count = 0;
+    for (var key in checks[i].data) {
+      count = count + 1;
+      ok(u.has(key), "key " + key + " found");
+
+      var all = u.getAll(key);
+      is(all.length, checks[i].data[key].length, "same number of elements");
+
+      for (var k = 0; k < all.length; ++k) {
+        is(all[k], checks[i].data[key][k], "value matches");
+      }
+    }
+  }
+
+  runTest();
+}
+
+function testEncoding() {
+  var encoding = [
+    ["1", "1"],
+    ["a b", "a+b"],
+    ["<>", "%3C%3E"],
+    ["\u0541", "%D5%81"],
+  ];
+
+  for (var i = 0; i < encoding.length; ++i) {
+    var url = new URL("http://www.example.net");
+    url.searchParams.set("a", encoding[i][0]);
+    is(url.href, "http://www.example.net/?a=" + encoding[i][1]);
+
+    var url2 = new URL(url.href);
+    is(url2.searchParams.get("a"), encoding[i][0], "a is still there");
+  }
+
+  runTest();
+}
+
+function testCopyConstructor() {
+  var url = new URL("http://example.com/");
+  var p = url.searchParams;
+  var q = new URLSearchParams(p);
+  q.set("a", "b");
+  is(
+    url.href,
+    "http://example.com/",
+    "Messing with copy of URLSearchParams should not affect URL"
+  );
+  p.set("c", "d");
+  is(
+    url.href,
+    "http://example.com/?c=d",
+    "Messing with URLSearchParams should affect URL"
+  );
+
+  runTest();
+}
+
+function testOrdering() {
+  var a = new URLSearchParams("a=1&a=2&b=3&c=4&c=5&a=6");
+  is(a.toString(), "a=1&a=2&b=3&c=4&c=5&a=6", "Order is correct");
+  is(a.getAll("a").length, 3, "Correct length of getAll()");
+
+  var b = new URLSearchParams();
+  b.append("a", "1");
+  b.append("b", "2");
+  b.append("a", "3");
+  is(b.toString(), "a=1&b=2&a=3", "Order is correct");
+  is(b.getAll("a").length, 2, "Correct length of getAll()");
+
+  runTest();
+}
+
+function testDelete() {
+  var a = new URLSearchParams("a=1&a=2&b=3&c=4&c=5&a=6");
+  is(a.toString(), "a=1&a=2&b=3&c=4&c=5&a=6", "Order is correct");
+  is(a.getAll("a").length, 3, "Correct length of getAll()");
+
+  a.delete("a");
+  is(a.getAll("a").length, 0, "Correct length of getAll()");
+  is(a.toString(), "b=3&c=4&c=5", "Order is correct");
+
+  runTest();
+}
+
+function testGetNULL() {
+  var u = new URLSearchParams();
+  is(typeof u.get(""), "object", "typeof URL.searchParams.get('')");
+  is(u.get(""), null, "URL.searchParams.get('') should be null");
+
+  var url = new URL("http://www.example.net?a=b");
+  is(
+    url.searchParams.get("b"),
+    null,
+    "URL.searchParams.get('b') should be null"
+  );
+  is(url.searchParams.get("a"), "b", "URL.searchParams.get('a')");
+
+  runTest();
+}
+
+function testSet() {
+  var u = new URLSearchParams();
+  u.set("a", "b");
+  u.set("e", "c");
+  u.set("i", "d");
+  u.set("o", "f");
+  u.set("u", "g");
+
+  is(u.get("a"), "b", "URL.searchParams.get('a') should return b");
+  is(u.getAll("a").length, 1, "URLSearchParams.getAll('a').length should be 1");
+
+  u.set("a", "h1");
+  u.set("a", "h2");
+  u.set("a", "h3");
+  u.set("a", "h4");
+  is(u.get("a"), "h4", "URL.searchParams.get('a') should return h4");
+  is(u.getAll("a").length, 1, "URLSearchParams.getAll('a').length should be 1");
+
+  is(u.get("e"), "c", "URL.searchParams.get('e') should return c");
+  is(u.get("i"), "d", "URL.searchParams.get('i') should return d");
+  is(u.get("o"), "f", "URL.searchParams.get('o') should return f");
+  is(u.get("u"), "g", "URL.searchParams.get('u') should return g");
+
+  is(u.getAll("e").length, 1, "URLSearchParams.getAll('e').length should be 1");
+  is(u.getAll("i").length, 1, "URLSearchParams.getAll('i').length should be 1");
+  is(u.getAll("o").length, 1, "URLSearchParams.getAll('o').length should be 1");
+  is(u.getAll("u").length, 1, "URLSearchParams.getAll('u').length should be 1");
+
+  u = new URLSearchParams("name1=value1&name1=value2&name1=value3");
+  is(
+    u.get("name1"),
+    "value1",
+    "URL.searchParams.get('name1') should return value1"
+  );
+  is(
+    u.getAll("name1").length,
+    3,
+    "URLSearchParams.getAll('name1').length should be 3"
+  );
+  u.set("name1", "firstPair");
+  is(
+    u.get("name1"),
+    "firstPair",
+    "URL.searchParams.get('name1') should return firstPair"
+  );
+  is(
+    u.getAll("name1").length,
+    1,
+    "URLSearchParams.getAll('name1').length should be 1"
+  );
+
+  runTest();
+}
+
+function testIterable() {
+  var u = new URLSearchParams();
+  u.set("1", "2");
+  u.set("2", "4");
+  u.set("3", "6");
+  u.set("4", "8");
+  u.set("5", "10");
+
+  var key_iter = u.keys();
+  var value_iter = u.values();
+  var entries_iter = u.entries();
+  for (var i = 0; i < 5; ++i) {
+    var v = i + 1;
+    var key = key_iter.next();
+    var value = value_iter.next();
+    var entry = entries_iter.next();
+    is(key.value, v.toString(), "Correct Key iterator: " + v.toString());
+    ok(!key.done, "Key.done is false");
+    is(
+      value.value,
+      (v * 2).toString(),
+      "Correct Value iterator: " + (v * 2).toString()
+    );
+    ok(!value.done, "Value.done is false");
+    is(
+      entry.value[0],
+      v.toString(),
+      "Correct Entry 0 iterator: " + v.toString()
+    );
+    is(
+      entry.value[1],
+      (v * 2).toString(),
+      "Correct Entry 1 iterator: " + (v * 2).toString()
+    );
+    ok(!entry.done, "Entry.done is false");
+  }
+
+  var last = key_iter.next();
+  ok(last.done, "Nothing more to read.");
+  is(last.value, undefined, "Undefined is the last key");
+
+  last = value_iter.next();
+  ok(last.done, "Nothing more to read.");
+  is(last.value, undefined, "Undefined is the last value");
+
+  last = entries_iter.next();
+  ok(last.done, "Nothing more to read.");
+
+  key_iter = u.keys();
+  key_iter.next();
+  key_iter.next();
+  u.delete("1");
+  u.delete("2");
+  u.delete("3");
+  u.delete("4");
+  u.delete("5");
+
+  last = key_iter.next();
+  ok(last.done, "Nothing more to read.");
+  is(last.value, undefined, "Undefined is the last key");
+
+  runTest();
+}
+function testZeroHandling() {
+  var u = new URLSearchParams();
+  u.set("a", "b\0c");
+  u.set("d\0e", "f");
+  u.set("g\0h", "i\0j");
+  is(
+    u.toString(),
+    "a=b%00c&d%00e=f&g%00h=i%00j",
+    "Should encode U+0000 as %00"
+  );
+
+  runTest();
+}
+
+function testCTORs() {
+  var a = new URLSearchParams("a=b");
+  is(a.get("a"), "b", "CTOR with string");
+
+  var b = new URLSearchParams([
+    ["a", "b"],
+    ["c", "d"],
+  ]);
+  is(b.get("a"), "b", "CTOR with sequence");
+  is(b.get("c"), "d", "CTOR with sequence");
+
+  ok(new URLSearchParams([]), "CTOR with empty sequence");
+
+  let result;
+  try {
+    result = new URLSearchParams([[1]]);
+  } catch (e) {
+    result = 42;
+  }
+
+  is(
+    result,
+    42,
+    "CTOR throws if the sequence doesn't contain exactly 2 elements"
+  );
+
+  try {
+    result = new URLSearchParams([[1, 2, 3]]);
+  } catch (e) {
+    result = 43;
+  }
+  is(
+    result,
+    43,
+    "CTOR throws if the sequence doesn't contain exactly 2 elements"
+  );
+
+  var c = new URLSearchParams({
+    a: "b",
+    c: 42,
+    d: null,
+    e: [1, 2, 3],
+    f: { a: 42 },
+  });
+  is(c.get("a"), "b", "CTOR with record<>");
+  is(c.get("c"), "42", "CTOR with record<>");
+  is(c.get("d"), "null", "CTOR with record<>");
+  is(c.get("e"), [1, 2, 3].toString(), "CTOR with record<>");
+  is(c.get("f"), { a: 42 }.toString(), "CTOR with record<>");
+
+  runTest();
+}
diff --git a/dom/url/tests/urlSearchParams_worker.js b/dom/url/tests/urlSearchParams_worker.js
new file mode 100644
index 0000000000..7959fd7d1c
--- /dev/null
+++ b/dom/url/tests/urlSearchParams_worker.js
@@ -0,0 +1,48 @@
+/* eslint-env worker */
+
+importScripts("urlSearchParams_commons.js");
+
+function ok(a, msg) {
+  dump("OK: " + !!a + "  =>  " + a + " " + msg + "\n");
+  postMessage({ type: "status", status: !!a, msg: a + ": " + msg });
+}
+
+function is(a, b, msg) {
+  dump("IS: " + (a === b) + "  =>  " + a + " | " + b + " " + msg + "\n");
+  postMessage({
+    type: "status",
+    status: a === b,
+    msg: a + " === " + b + ": " + msg,
+  });
+}
+
+var tests = [
+  testSimpleURLSearchParams,
+  testCopyURLSearchParams,
+  testParserURLSearchParams,
+  testURL,
+  testEncoding,
+  testCTORs,
+];
+
+function runTest() {
+  if (!tests.length) {
+    postMessage({ type: "finish" });
+    return;
+  }
+
+  var test = tests.shift();
+  test();
+}
+
+onmessage = function () {
+  let status = false;
+  try {
+    if (URLSearchParams instanceof Object) {
+      status = true;
+    }
+  } catch (e) {}
+  ok(status, "URLSearchParams in workers \\o/");
+
+  runTest();
+};
diff --git a/dom/url/tests/url_exceptions_worker.js b/dom/url/tests/url_exceptions_worker.js
new file mode 100644
index 0000000000..c8d8494ac9
--- /dev/null
+++ b/dom/url/tests/url_exceptions_worker.js
@@ -0,0 +1,38 @@
+function ok(a, msg) {
+  postMessage({ type: "status", status: !!a, msg });
+}
+
+onmessage = function (event) {
+  // URL.href throws
+  var url = new URL("http://www.example.com");
+  ok(url, "URL created");
+
+  var status = false;
+  try {
+    url.href = "42";
+  } catch (e) {
+    status = true;
+  }
+  ok(status, "url.href = 42 should throw");
+
+  url.href = "http://www.example.org";
+  ok(true, "url.href should not throw");
+
+  status = false;
+  try {
+    new URL("42");
+  } catch (e) {
+    status = true;
+  }
+  ok(status, "new URL(42) should throw");
+
+  status = false;
+  try {
+    new URL("http://www.example.com", "42");
+  } catch (e) {
+    status = true;
+  }
+  ok(status, "new URL(something, 42) should throw");
+
+  postMessage({ type: "finish" });
+};
diff --git a/dom/url/tests/url_worker.js b/dom/url/tests/url_worker.js
new file mode 100644
index 0000000000..8a69744603
--- /dev/null
+++ b/dom/url/tests/url_worker.js
@@ -0,0 +1,98 @@
+/* eslint-env worker */
+
+onmessage = function (event) {
+  if (event.data != 0) {
+    var worker = new Worker("url_worker.js");
+    worker.onmessage = function (ev) {
+      postMessage(ev.data);
+    };
+
+    worker.postMessage(event.data - 1);
+    return;
+  }
+
+  let status = false;
+  try {
+    if (URL instanceof Object) {
+      status = true;
+    }
+  } catch (e) {}
+
+  postMessage({ type: "status", status, msg: "URL object:" + URL });
+
+  status = false;
+  var blob = null;
+  try {
+    blob = new Blob([]);
+    status = true;
+  } catch (e) {}
+
+  postMessage({ type: "status", status, msg: "Blob:" + blob });
+
+  status = false;
+  let url = null;
+  try {
+    url = URL.createObjectURL(blob);
+    status = true;
+  } catch (e) {}
+
+  postMessage({ type: "status", status, msg: "Blob URL:" + url });
+
+  status = false;
+  try {
+    URL.revokeObjectURL(url);
+    status = true;
+  } catch (e) {}
+
+  postMessage({ type: "status", status, msg: "Blob Revoke URL" });
+
+  status = false;
+  url = null;
+  try {
+    url = URL.createObjectURL(true);
+  } catch (e) {
+    status = true;
+  }
+
+  postMessage({
+    type: "status",
+    status,
+    msg: "CreateObjectURL should fail if the arg is not a blob",
+  });
+
+  status = false;
+  url = null;
+  try {
+    url = URL.createObjectURL(blob);
+    status = true;
+  } catch (e) {}
+
+  postMessage({ type: "status", status, msg: "Blob URL2:" + url });
+  postMessage({ type: "url", url });
+
+  status = false;
+  try {
+    URL.createObjectURL({});
+  } catch (e) {
+    status = true;
+  }
+
+  postMessage({ type: "status", status, msg: "Exception wanted" });
+
+  blob = new Blob([123]);
+  var uri = URL.createObjectURL(blob);
+  postMessage({
+    type: "status",
+    status: !!uri,
+    msg: "The URI has been generated from the blob",
+  });
+
+  var u = new URL(uri);
+  postMessage({
+    type: "status",
+    status: u.origin == location.origin,
+    msg: "The URL generated from a blob URI has an origin.",
+  });
+
+  postMessage({ type: "finish" });
+};
-- 
cgit v1.2.3