summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/clear-site-data/support
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--testing/web-platform/tests/clear-site-data/support/clear-site-data-cookie.py16
-rw-r--r--testing/web-platform/tests/clear-site-data/support/controlled-endpoint.py3
-rw-r--r--testing/web-platform/tests/clear-site-data/support/echo-clear-site-data.py40
-rw-r--r--testing/web-platform/tests/clear-site-data/support/iframe_executionContexts.html8
-rw-r--r--testing/web-platform/tests/clear-site-data/support/page_using_service_worker.html6
-rw-r--r--testing/web-platform/tests/clear-site-data/support/page_with_resource.sub.html27
-rw-r--r--testing/web-platform/tests/clear-site-data/support/send_report.html24
-rw-r--r--testing/web-platform/tests/clear-site-data/support/service_worker.js6
-rw-r--r--testing/web-platform/tests/clear-site-data/support/test_utils.sub.js261
9 files changed, 391 insertions, 0 deletions
diff --git a/testing/web-platform/tests/clear-site-data/support/clear-site-data-cookie.py b/testing/web-platform/tests/clear-site-data/support/clear-site-data-cookie.py
new file mode 100644
index 0000000000..eb50cb54ef
--- /dev/null
+++ b/testing/web-platform/tests/clear-site-data/support/clear-site-data-cookie.py
@@ -0,0 +1,16 @@
+"""
+Step 2/3 (/clear-site-data/set-cookie-{}-clear-{}.https.html)
+"""
+def main(request, response):
+ headers = [(b"Content-Type", b"text/html")]
+ clear_site_data_header = (b"Clear-Site-Data", b"\"" + request.GET.first(b"target", b"*") + b"\"")
+ set_cookie_header = (b"Set-Cookie", b"testSetWithClear=true")
+ if request.GET.first(b"location") == b"after":
+ headers = headers + [clear_site_data_header, set_cookie_header]
+ else:
+ headers = headers + [set_cookie_header, clear_site_data_header]
+ content = u'''
+ <script>
+ window.opener.postMessage(document.cookie , "*");
+ </script>'''
+ return 200, headers, content
diff --git a/testing/web-platform/tests/clear-site-data/support/controlled-endpoint.py b/testing/web-platform/tests/clear-site-data/support/controlled-endpoint.py
new file mode 100644
index 0000000000..bb4f464088
--- /dev/null
+++ b/testing/web-platform/tests/clear-site-data/support/controlled-endpoint.py
@@ -0,0 +1,3 @@
+def main(request, response):
+ return ([(b"Content-Type", b"text/html")],
+ u"FROM_NETWORK")
diff --git a/testing/web-platform/tests/clear-site-data/support/echo-clear-site-data.py b/testing/web-platform/tests/clear-site-data/support/echo-clear-site-data.py
new file mode 100644
index 0000000000..6419d5bfad
--- /dev/null
+++ b/testing/web-platform/tests/clear-site-data/support/echo-clear-site-data.py
@@ -0,0 +1,40 @@
+import json
+
+RESPONSE = u"""
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Clear-Site-Data</title>
+ <script src="test_utils.sub.js"></script>
+ </head>
+ <body>
+ <script>
+ /**
+ * A map between a datatype name and whether it is empty.
+ * @property Object.<string, boolean>
+ */
+ var report = {};
+
+ Promise.all(TestUtils.DATATYPES.map(function(datatype) {
+ return datatype.isEmpty().then(function(isEmpty) {
+ report[datatype.name] = isEmpty;
+ });
+ })).then(function() {
+ window.top.postMessage(report, "*");
+ });
+ </script>
+ </body>
+</html>
+"""
+
+# A support server that receives a list of datatypes in the GET query
+# and returns a Clear-Site-Data header with those datatypes. The content
+# of the response is a html site using postMessage to report the status
+# of the datatypes, so that if used in an iframe, it can inform the
+# embedder whether the data deletion succeeded.
+def main(request, response):
+ types = [key for key in request.GET.keys()]
+ header = b",".join(b"\"" + type + b"\"" for type in types)
+ return ([(b"Clear-Site-Data", header),
+ (b"Content-Type", b"text/html")],
+ RESPONSE)
diff --git a/testing/web-platform/tests/clear-site-data/support/iframe_executionContexts.html b/testing/web-platform/tests/clear-site-data/support/iframe_executionContexts.html
new file mode 100644
index 0000000000..9c20c9e0db
--- /dev/null
+++ b/testing/web-platform/tests/clear-site-data/support/iframe_executionContexts.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+ <body>
+ <script>
+ parent.postMessage("Hello world!", "*");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/clear-site-data/support/page_using_service_worker.html b/testing/web-platform/tests/clear-site-data/support/page_using_service_worker.html
new file mode 100644
index 0000000000..968a39a132
--- /dev/null
+++ b/testing/web-platform/tests/clear-site-data/support/page_using_service_worker.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Clear-Site-Data + Service Workers Test Page</title>
+ </head>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/clear-site-data/support/page_with_resource.sub.html b/testing/web-platform/tests/clear-site-data/support/page_with_resource.sub.html
new file mode 100644
index 0000000000..703519a2f6
--- /dev/null
+++ b/testing/web-platform/tests/clear-site-data/support/page_with_resource.sub.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Clear-Site-Data</title>
+ <script src="test_utils.sub.js"></script>
+ </head>
+ <body>
+ <script>
+ var scheme = location.search.match("scheme=([^&$]+)")[1];
+
+ // TODO(@msramek): Move this logic to TestUtils.
+ var base_url = location.origin
+ .replace(/https?/, scheme)
+ .replace(/:[0-9]+/, ":" + (scheme == "https" ? {{ports[https][0]}}
+ : {{ports[http][0]}})) +
+ "/clear-site-data/support/";
+
+ var image = new Image();
+ image.onload = image.onerror = function() {
+ location.href = base_url + "send_report.html";
+ }
+
+ // TODO(@msramek): Move this logic to TestUtils.
+ image.src = base_url + "echo-clear-site-data.py?storage";
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/clear-site-data/support/send_report.html b/testing/web-platform/tests/clear-site-data/support/send_report.html
new file mode 100644
index 0000000000..6e90c626ea
--- /dev/null
+++ b/testing/web-platform/tests/clear-site-data/support/send_report.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Clear-Site-Data</title>
+ <script src="test_utils.sub.js"></script>
+ </head>
+ <body>
+ <script>
+ /**
+ * A map between a datatype name and whether it is empty.
+ * @property Object.<string, boolean>
+ */
+ var report = {};
+
+ Promise.all(TestUtils.DATATYPES.map(function(datatype) {
+ return datatype.isEmpty().then(function(isEmpty) {
+ report[datatype.name] = isEmpty;
+ });
+ })).then(function() {
+ window.top.postMessage(report, "*");
+ });
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/clear-site-data/support/service_worker.js b/testing/web-platform/tests/clear-site-data/support/service_worker.js
new file mode 100644
index 0000000000..a4e5709ee1
--- /dev/null
+++ b/testing/web-platform/tests/clear-site-data/support/service_worker.js
@@ -0,0 +1,6 @@
+self.addEventListener('fetch', (e) => {
+ const url = new URL(e.request.url);
+ if (url.pathname.match('controlled-endpoint.py')) {
+ e.respondWith(new Response('FROM_SERVICE_WORKER'));
+ }
+}); \ No newline at end of file
diff --git a/testing/web-platform/tests/clear-site-data/support/test_utils.sub.js b/testing/web-platform/tests/clear-site-data/support/test_utils.sub.js
new file mode 100644
index 0000000000..71fc79c420
--- /dev/null
+++ b/testing/web-platform/tests/clear-site-data/support/test_utils.sub.js
@@ -0,0 +1,261 @@
+var TestUtils = (function() {
+ function randomString() {
+ var result = "";
+ for (var i = 0; i < 5; i++)
+ result += String.fromCharCode(97 + Math.floor(Math.random() * 26));
+ return result;
+ };
+
+ /**
+ * Representation of one datatype.
+ * @typedef Datatype
+ * @type{object}
+ * @property{string} name Name of the datatype.
+ * @property{function():boolean} supported
+ * Whether this datatype is supported by this user agent.
+ * @method{function():Void} add A function to add an instance of the datatype.
+ * @method{function():boolean} isEmpty A function that tests whether
+ * the datatype's storage backend is empty.
+ */
+ var Datatype;
+
+ var TestUtils = {};
+
+ /**
+ * Various storage backends that are part of the 'storage' datatype.
+ * @param{Array.<Datatype>}
+ */
+ TestUtils.STORAGE = [
+ {
+ "name": "local storage",
+ "supported": function() { return !!window.localStorage; },
+ "add": function() {
+ return new Promise(function(resolve, reject) {
+ localStorage.setItem(randomString(), randomString());
+ resolve();
+ });
+ },
+ "isEmpty": function() {
+ return new Promise(function(resolve, reject) {
+ resolve(!localStorage.length);
+ });
+ }
+ },
+ {
+ "name": "Indexed DB",
+ "supported": function() { return !!window.indexedDB; },
+ "add": function() {
+ return new Promise(function(resolve, reject) {
+ var request = window.indexedDB.open("database");
+ request.onupgradeneeded = function() {
+ request.result.createObjectStore("store");
+ };
+ request.onsuccess = function() {
+ request.result.close();
+ resolve();
+ }
+ });
+ },
+ "isEmpty": function() {
+ return new Promise(function(resolve, reject) {
+ var request = window.indexedDB.open("database");
+ request.onsuccess = function() {
+ var database = request.result;
+ try {
+ var transaction = database.transaction(["store"]);
+ resolve(false);
+ } catch(error) {
+ // The database is empty. However, by testing that, we have also
+ // created it, which means that |onupgradeneeded| in the "add"
+ // method will not run the next time. Delete the database before
+ // reporting that it was empty.
+ var deletion = window.indexedDB.deleteDatabase("database");
+ deletion.onsuccess = resolve.bind(this, true);
+ } finally {
+ database.close();
+ }
+ };
+ });
+ }
+ },
+ {
+ // TODO(@msramek): We should also test the PERSISTENT filesystem, however,
+ // that might require storage permissions.
+ "name": "filesystems",
+ "supported": function() {
+ return window.requestFileSystem || window.webkitRequestFileSystem;
+ },
+ "add": function() {
+ return new Promise(function(resolve, reject) {
+ var onSuccess = function(fileSystem) {
+ fileSystem.root.getFile('file', {"create": true}, resolve, resolve);
+ }
+ var onFailure = resolve;
+
+ var requestFileSystem =
+ window.requestFileSystem || window.webkitRequestFileSystem;
+ requestFileSystem(window.TEMPORARY, 1 /* 1B */,
+ onSuccess, onFailure);
+ });
+ },
+ "isEmpty": function() {
+ return new Promise(function(resolve, reject) {
+ var onSuccess = function(fileSystem) {
+ fileSystem.root.getFile(
+ 'file', {},
+ resolve.bind(this, false) /* opened successfully */,
+ resolve.bind(this, true) /* failed to open */);
+ }
+ var onFailure = resolve.bind(this, true);
+
+ var requestFileSystem =
+ window.requestFileSystem || window.webkitRequestFileSystem;
+ requestFileSystem(window.TEMPORARY, 1 /* 1B */,
+ onSuccess, onFailure);
+ });
+ }
+ },
+ {
+ "name": "service workers",
+ "supported": function() { return !!navigator.serviceWorker; },
+ "add": function() {
+ return navigator.serviceWorker.register(
+ "support/service_worker.js",
+ { scope: "support/page_using_service_worker.html"});
+ },
+ "isEmpty": function() {
+ return new Promise(function(resolve, reject) {
+ navigator.serviceWorker.getRegistrations()
+ .then(function(registrations) {
+ resolve(!registrations.length);
+ });
+ });
+ }
+ },
+ {
+ "name": "Storage Buckets",
+ "supported": function() { return !!navigator.storageBuckets; },
+ "add": function() {
+ return navigator.storageBuckets.open('inbox_bucket');
+ },
+ "isEmpty": function() {
+ return new Promise(async function(resolve, reject) {
+ var keys = await navigator.storageBuckets.keys();
+ resolve(!keys.includes('inbox_bucket'));
+ });
+ }
+ },
+ ].filter(function(backend) { return backend.supported(); });
+
+ /**
+ * All datatypes supported by Clear-Site-Data.
+ * @param{Array.<Datatype>}
+ */
+ TestUtils.DATATYPES = [
+ {
+ "name": "cookies",
+ "supported": function() { return typeof document.cookie == "string"; },
+ "add": function() {
+ return new Promise(function(resolve, reject) {
+ document.cookie = randomString() + "=" + randomString();
+ resolve();
+ });
+ },
+ "isEmpty": function() {
+ return new Promise(function(resolve, reject) {
+ resolve(!document.cookie);
+ });
+ }
+ },
+ {
+ "name": "storage",
+ "supported": TestUtils.STORAGE[0].supported,
+ "add": TestUtils.STORAGE[0].add,
+ "isEmpty": TestUtils.STORAGE[0].isEmpty,
+ }
+ ].filter(function(datatype) { return datatype.supported(); });
+
+ /**
+ * All possible combinations of datatypes.
+ * @property {Array.<Array.<Datatype>>}
+ */
+ TestUtils.COMBINATIONS = (function() {
+ var combinations = [];
+ for (var mask = 0; mask < (1 << TestUtils.DATATYPES.length); mask++) {
+ var combination = [];
+
+ for (var datatype = 0;
+ datatype < TestUtils.DATATYPES.length; datatype++) {
+ if (mask & (1 << datatype))
+ combination.push(TestUtils.DATATYPES[datatype]);
+ }
+
+ combinations.push(combination);
+ }
+ return combinations;
+ })();
+
+ /**
+ * Populates |datatypes| by calling the "add" method on each of them,
+ * and verifies that they are nonempty.
+ * @param {Array.<Datatype>} datatypes to be populated.
+ * @private
+ */
+ function populate(datatypes) {
+ return Promise.all(datatypes.map(function(datatype) {
+ return new Promise(function(resolve, reject) {
+ datatype.add().then(function() {
+ datatype.isEmpty().then(function(isEmpty) {
+ assert_false(
+ isEmpty,
+ datatype.name +
+ " has to be nonempty before the test starts.");
+ resolve();
+ });
+ });
+ });
+ }));
+ };
+
+ /**
+ * Ensures that all datatypes are nonempty. Should be called in the test
+ * setup phase.
+ */
+ TestUtils.populateDatatypes = populate.bind(this, TestUtils.DATATYPES);
+
+ /**
+ * Ensures that all backends of the "storage" datatype are nonempty. Should
+ * be called in the test setup phase.
+ */
+ TestUtils.populateStorage = populate.bind(this, TestUtils.STORAGE);
+
+ /**
+ * Get the support server URL that returns a Clear-Site-Data header
+ * to clear |datatypes|.
+ * @param{Array.<Datatype>} datatypes The list of datatypes to be deleted.
+ * @return string The URL to be queried.
+ */
+ TestUtils.getClearSiteDataUrl = function(datatypes) {
+ names = datatypes.map(function(e) { return e.name });
+ return "support/echo-clear-site-data.py?" + names.join("&");
+ }
+
+ /**
+ * @param{string} page_scheme Scheme of the page. "http" or "https".
+ * @param{string} resource_scheme Scheme of the resource. "http" or "https".
+ * @return The URL of a page that contains a resource requesting the deletion
+ * of storage.
+ */
+ TestUtils.getPageWithResourceUrl = function(page_scheme, resource_scheme) {
+ if (page_scheme != "https" && page_scheme != "http")
+ throw "Unsupported scheme: " + page_scheme;
+ if (resource_scheme != "https" && resource_scheme != "http")
+ throw "Unsupported scheme: " + resource_scheme;
+ return page_scheme + "://{{domains[]}}:" +
+ (page_scheme == "https" ? {{ports[https][0]}} : {{ports[http][0]}}) +
+ "/clear-site-data/support/page_with_resource.sub.html?scheme=" +
+ resource_scheme;
+ }
+
+ return TestUtils;
+})();