diff --git a/FileAPI/BlobURL/support/file_test1.js b/FileAPI/BlobURL/support/file_test1.js
deleted file mode 100644
index 34983584999db4..00000000000000
--- a/FileAPI/BlobURL/support/file_test1.js
+++ /dev/null
@@ -1 +0,0 @@
-var test_result = 'test1_OK';
\ No newline at end of file
diff --git a/FileAPI/BlobURL/support/file_test3.html b/FileAPI/BlobURL/support/file_test3.html
deleted file mode 100644
index fa234cb9f997fd..00000000000000
--- a/FileAPI/BlobURL/support/file_test3.html
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
- Test file
-
-
-
-
-
-
-
-
-
-
-
diff --git a/FileAPI/BlobURL/test1-manual.html b/FileAPI/BlobURL/test1-manual.html
deleted file mode 100644
index 8da42cf647ad68..00000000000000
--- a/FileAPI/BlobURL/test1-manual.html
+++ /dev/null
@@ -1,122 +0,0 @@
-
-
-
-
- Blob and File reference URL Test(1)
-
-
-
-
-
-
-
-
-
-
Test steps:
-
- - Download the file.
- - Select the file in the file inputbox to run the test.
-
-
-
-
-
-
-
-
diff --git a/FileAPI/BlobURL/test3-manual.html b/FileAPI/BlobURL/test3-manual.html
deleted file mode 100644
index ce020a7b74dc1c..00000000000000
--- a/FileAPI/BlobURL/test3-manual.html
+++ /dev/null
@@ -1,71 +0,0 @@
-
-
-
-
- Blob and File reference URL Test(3)
-
-
-
-
-
-
-
-
-
-
Test steps:
-
- - Download the file.
- - Select the file in the file inputbox and the test will start.
-
-
-
-
-
-
-
-
diff --git a/FileAPI/blob/Blob-Request-revoke-fetch.html b/FileAPI/blob/Blob-Request-revoke-fetch.html
deleted file mode 100644
index 2cac5343cd813f..00000000000000
--- a/FileAPI/blob/Blob-Request-revoke-fetch.html
+++ /dev/null
@@ -1,41 +0,0 @@
-
-Revoking blob URL used with Request/fetch
-
-
-
-
diff --git a/FileAPI/blob/Blob-XHR-revoke.html b/FileAPI/blob/Blob-XHR-revoke.html
deleted file mode 100644
index a38caaf3221023..00000000000000
--- a/FileAPI/blob/Blob-XHR-revoke.html
+++ /dev/null
@@ -1,38 +0,0 @@
-
-Revoking blob URL used with XMLHttpRequest
-
-
-
-
diff --git a/FileAPI/url/blob-url-in-sandboxed-iframe.html b/FileAPI/url/blob-url-in-sandboxed-iframe.html
deleted file mode 100644
index 7d032496c763c2..00000000000000
--- a/FileAPI/url/blob-url-in-sandboxed-iframe.html
+++ /dev/null
@@ -1,66 +0,0 @@
-
-
-FileAPI Test: Creating Blob URL with Blob
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/FileAPI/url/cross-global-revoke.sub.html b/FileAPI/url/cross-global-revoke.sub.html
new file mode 100644
index 00000000000000..f39a8bec169a40
--- /dev/null
+++ b/FileAPI/url/cross-global-revoke.sub.html
@@ -0,0 +1,61 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/FileAPI/url/resources/create-helper.html b/FileAPI/url/resources/create-helper.html
new file mode 100644
index 00000000000000..fa6cf4e671e835
--- /dev/null
+++ b/FileAPI/url/resources/create-helper.html
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/FileAPI/url/resources/create-helper.js b/FileAPI/url/resources/create-helper.js
new file mode 100644
index 00000000000000..e6344f700ced60
--- /dev/null
+++ b/FileAPI/url/resources/create-helper.js
@@ -0,0 +1,4 @@
+self.addEventListener('message', e => {
+ let url = URL.createObjectURL(e.data.blob);
+ self.postMessage({url: url});
+});
diff --git a/FileAPI/url/resources/fetch-tests.js b/FileAPI/url/resources/fetch-tests.js
new file mode 100644
index 00000000000000..a81ea1e7b1de35
--- /dev/null
+++ b/FileAPI/url/resources/fetch-tests.js
@@ -0,0 +1,71 @@
+// This method generates a number of tests verifying fetching of blob URLs,
+// allowing the same tests to be used both with fetch() and XMLHttpRequest.
+//
+// |fetch_method| is only used in test names, and should describe the
+// (javascript) method being used by the other two arguments (i.e. 'fetch' or 'XHR').
+//
+// |fetch_should_succeed| is a callback that is called with the Test and a URL.
+// Fetching the URL is expected to succeed. The callback should return a promise
+// resolved with whatever contents were fetched.
+//
+// |fetch_should_fail| similarly is a callback that is called with the Test, a URL
+// to fetch, and optionally a method to use to do the fetch. If no method is
+// specified the callback should use the 'GET' method. Fetching of these URLs is
+// expected to fail, and the callback should return a promise that resolves iff
+// fetching did indeed fail.
+function fetch_tests(fetch_method, fetch_should_succeed, fetch_should_fail) {
+ const blob_contents = 'test blob contents';
+ const blob = new Blob([blob_contents]);
+
+ promise_test(t => {
+ const url = URL.createObjectURL(blob);
+
+ return fetch_should_succeed(t, url).then(text => {
+ assert_equals(text, blob_contents);
+ });
+ }, 'Blob URLs can be used in ' + fetch_method);
+
+ promise_test(t => {
+ const url = URL.createObjectURL(blob);
+
+ return fetch_should_succeed(t, url + '#fragment').then(text => {
+ assert_equals(text, blob_contents);
+ });
+ }, fetch_method + ' with a fragment should succeed');
+
+ promise_test(t => {
+ const url = URL.createObjectURL(blob);
+ URL.revokeObjectURL(url);
+
+ return fetch_should_fail(t, url);
+ }, fetch_method + ' of a revoked URL should fail');
+
+ promise_test(t => {
+ const url = URL.createObjectURL(blob);
+ URL.revokeObjectURL(url + '#fragment');
+
+ return fetch_should_succeed(t, url).then(text => {
+ assert_equals(text, blob_contents);
+ });
+ }, 'Only exact matches should revoke URLs, using ' + fetch_method);
+
+ promise_test(t => {
+ const url = URL.createObjectURL(blob);
+
+ return fetch_should_fail(t, url + '?querystring');
+ }, 'Appending a query string should cause ' + fetch_method + ' to fail');
+
+ promise_test(t => {
+ const url = URL.createObjectURL(blob);
+
+ return fetch_should_fail(t, url + '/path');
+ }, 'Appending a path should cause ' + fetch_method + ' to fail');
+
+ for (const method of ['HEAD', 'POST', 'DELETE', 'OPTIONS', 'PUT', 'CUSTOM']) {
+ const url = URL.createObjectURL(blob);
+
+ promise_test(t => {
+ return fetch_should_fail(t, url, method);
+ }, fetch_method + ' with method "' + method + '" should fail');
+ }
+}
\ No newline at end of file
diff --git a/FileAPI/url/resources/revoke-helper.html b/FileAPI/url/resources/revoke-helper.html
new file mode 100644
index 00000000000000..adf5a014a668d6
--- /dev/null
+++ b/FileAPI/url/resources/revoke-helper.html
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/FileAPI/url/resources/revoke-helper.js b/FileAPI/url/resources/revoke-helper.js
new file mode 100644
index 00000000000000..28afce7a259092
--- /dev/null
+++ b/FileAPI/url/resources/revoke-helper.js
@@ -0,0 +1,4 @@
+self.addEventListener('message', e => {
+ URL.revokeObjectURL(e.data.url);
+ self.postMessage('revoked');
+});
diff --git a/FileAPI/url/sandboxed-iframe.html b/FileAPI/url/sandboxed-iframe.html
new file mode 100644
index 00000000000000..e7a8a15daa9e30
--- /dev/null
+++ b/FileAPI/url/sandboxed-iframe.html
@@ -0,0 +1,30 @@
+
+
+FileAPI Test: Verify behavior of Blob URL in unique origins
+
+
+
+
+
+
\ No newline at end of file
diff --git a/FileAPI/url/origin.sub.html b/FileAPI/url/unicode-origin.sub.html
similarity index 75%
rename from FileAPI/url/origin.sub.html
rename to FileAPI/url/unicode-origin.sub.html
index 56c8fa4835d2c5..2c4921c0344998 100644
--- a/FileAPI/url/origin.sub.html
+++ b/FileAPI/url/unicode-origin.sub.html
@@ -5,14 +5,6 @@
';
+ const blob = new Blob([blob_contents], {type: 'text/html'});
+ const url = URL.createObjectURL(blob);
+
+ const frame = document.createElement('iframe');
+ frame.setAttribute('src', url);
+ frame.setAttribute('style', 'display:none;');
+ document.body.appendChild(frame);
+
+ frame.onload = t.step_func_done(() => {
+ assert_equals(frame.contentWindow.test_result, run_result);
+ });
+}, 'Blob URLs can be used in iframes, and are treated same origin');
+
+async_test(t => {
+ const scroll_position = 5000;
+ const blob_contents = '\n\n' +
+ '\n' +
+ '\n' +
+ '\n' +
+ '';
+ const blob = new Blob([blob_contents], {type: 'text/html'});
+ const url = URL.createObjectURL(blob);
+
+ const frame = document.createElement('iframe');
+ frame.setAttribute('src', url + '#block2');
+ document.body.appendChild(frame);
+
+ frame.onload = t.step_func_done(() => {
+ assert_equals(frame.contentWindow.scrollY, 5000);
+ });
+}, 'Blob URL fragment is implemented.');
diff --git a/FileAPI/url/url-lifetime.html b/FileAPI/url/url-lifetime.html
new file mode 100644
index 00000000000000..3c8345cfbbc645
--- /dev/null
+++ b/FileAPI/url/url-lifetime.html
@@ -0,0 +1,56 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/FileAPI/url/url-with-fetch.any.js b/FileAPI/url/url-with-fetch.any.js
new file mode 100644
index 00000000000000..775d9a0f474a51
--- /dev/null
+++ b/FileAPI/url/url-with-fetch.any.js
@@ -0,0 +1,53 @@
+// META: script=resources/fetch-tests.js
+
+function fetch_should_succeed(test, request) {
+ return fetch(request).then(response => response.text());
+}
+
+function fetch_should_fail(test, url, method = 'GET') {
+ return promise_rejects(test, new TypeError, fetch(url, {method: method}));
+}
+
+fetch_tests('fetch', fetch_should_succeed, fetch_should_fail);
+
+promise_test(t => {
+ const blob_contents = 'test blob contents';
+ const blob_type = 'image/png';
+ const blob = new Blob([blob_contents], {type: blob_type});
+ const url = URL.createObjectURL(blob);
+
+ return fetch(url).then(response => {
+ assert_equals(response.headers.get('Content-Type'), blob_type);
+ });
+}, 'fetch should return Content-Type from Blob');
+
+promise_test(t => {
+ const blob_contents = 'test blob contents';
+ const blob = new Blob([blob_contents]);
+ const url = URL.createObjectURL(blob);
+ const request = new Request(url);
+
+ // Revoke the object URL. Request should take a reference to the blob as
+ // soon as it receives it in open(), so the request succeeds even though we
+ // revoke the URL before calling fetch().
+ URL.revokeObjectURL(url);
+
+ return fetch_should_succeed(t, request).then(text => {
+ assert_equals(text, blob_contents);
+ });
+}, 'Revoke blob URL after creating Request, will fetch');
+
+promise_test(function(t) {
+ const blob_contents = 'test blob contents';
+ const blob = new Blob([blob_contents]);
+ const url = URL.createObjectURL(blob);
+
+ const result = fetch_should_succeed(t, url).then(text => {
+ assert_equals(text, blob_contents);
+ });
+
+ // Revoke the object URL. fetch should have already resolved the blob URL.
+ URL.revokeObjectURL(url);
+
+ return result;
+}, 'Revoke blob URL after calling fetch, fetch should succeed');
diff --git a/FileAPI/url/url-with-xhr.any.js b/FileAPI/url/url-with-xhr.any.js
new file mode 100644
index 00000000000000..29d83080ab5845
--- /dev/null
+++ b/FileAPI/url/url-with-xhr.any.js
@@ -0,0 +1,68 @@
+// META: script=resources/fetch-tests.js
+
+function xhr_should_succeed(test, url) {
+ return new Promise((resolve, reject) => {
+ const xhr = new XMLHttpRequest();
+ xhr.open('GET', url);
+ xhr.onload = test.step_func(() => {
+ assert_equals(xhr.status, 200);
+ assert_equals(xhr.statusText, 'OK');
+ resolve(xhr.response);
+ });
+ xhr.onerror = () => reject('Got unexpected error event');
+ xhr.send();
+ });
+}
+
+function xhr_should_fail(test, url, method = 'GET') {
+ const xhr = new XMLHttpRequest();
+ xhr.open(method, url);
+ const result1 = new Promise((resolve, reject) => {
+ xhr.onload = () => reject('Got unexpected load event');
+ xhr.onerror = resolve;
+ });
+ const result2 = new Promise(resolve => {
+ xhr.onreadystatechange = test.step_func(() => {
+ if (xhr.readyState !== xhr.DONE) return;
+ assert_equals(xhr.status, 0);
+ resolve();
+ });
+ });
+ xhr.send();
+ return Promise.all([result1, result2]);
+}
+
+fetch_tests('XHR', xhr_should_succeed, xhr_should_fail);
+
+async_test(t => {
+ const blob_contents = 'test blob contents';
+ const blob_type = 'image/png';
+ const blob = new Blob([blob_contents], {type: blob_type});
+ const url = URL.createObjectURL(blob);
+ const xhr = new XMLHttpRequest();
+ xhr.open('GET', url);
+ xhr.onloadend = t.step_func_done(() => {
+ assert_equals(xhr.getResponseHeader('Content-Type'), blob_type);
+ });
+ xhr.send();
+}, 'XHR should return Content-Type from Blob');
+
+async_test(t => {
+ const blob_contents = 'test blob contents';
+ const blob = new Blob([blob_contents]);
+ const url = URL.createObjectURL(blob);
+ const xhr = new XMLHttpRequest();
+ xhr.open('GET', url);
+
+ // Revoke the object URL. XHR should take a reference to the blob as soon as
+ // it receives it in open(), so the request succeeds even though we revoke the
+ // URL before calling send().
+ URL.revokeObjectURL(url);
+
+ xhr.onload = t.step_func_done(() => {
+ assert_equals(xhr.response, blob_contents);
+ });
+ xhr.onerror = t.unreached_func('Got unexpected error event');
+
+ xhr.send();
+}, 'Revoke blob URL after open(), will fetch');
diff --git a/FileAPI/url/url_createobjecturl_blob.html b/FileAPI/url/url_createobjecturl_blob.html
deleted file mode 100644
index 798df08de65a0d..00000000000000
--- a/FileAPI/url/url_createobjecturl_blob.html
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-FileAPI Test: Creating Blob URL with Blob
-
-
-
-
-
-
-
-
-
diff --git a/FileAPI/url/url_xmlhttprequest.html b/FileAPI/url/url_xmlhttprequest.html
deleted file mode 100644
index 7a86cdd1e80b46..00000000000000
--- a/FileAPI/url/url_xmlhttprequest.html
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-FileAPI Test: Creating Blob URL via XMLHttpRequest
-
-
-
-
-
-
-
-
-