diff options
Diffstat (limited to 'testing/web-platform/tests/referrer-policy/generic')
35 files changed, 1573 insertions, 0 deletions
diff --git a/testing/web-platform/tests/referrer-policy/generic/common.js b/testing/web-platform/tests/referrer-policy/generic/common.js new file mode 100644 index 000000000..492031859 --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/common.js @@ -0,0 +1,212 @@ +// NOTE: This method only strips the fragment and is not in accordance to the +// recommended draft specification: +// https://w3c.github.io/webappsec/specs/referrer-policy/#null +// TODO(kristijanburnik): Implement this helper as defined by spec once added +// scenarios for URLs containing username/password/etc. +function stripUrlForUseAsReferrer(url) { + return url.replace(/#.*$/, ""); +} + +function parseUrlQueryString(queryString) { + var queries = queryString.replace(/^\?/, "").split("&"); + var params = {}; + + for (var i in queries) { + var kvp = queries[i].split("="); + params[kvp[0]] = kvp[1]; + } + + return params; +}; + +function appendIframeToBody(url, attributes) { + var iframe = document.createElement("iframe"); + iframe.src = url; + // Extend element with attributes. (E.g. "referrerPolicy" or "rel") + if (attributes) { + for (var attr in attributes) { + iframe[attr] = attributes[attr]; + } + } + document.body.appendChild(iframe); + + return iframe; +} + +function loadImage(src, callback, attributes) { + var image = new Image(); + image.crossOrigin = "Anonymous"; + image.onload = function() { + callback(image); + } + image.src = src; + // Extend element with attributes. (E.g. "referrerPolicy" or "rel") + if (attributes) { + for (var attr in attributes) { + image[attr] = attributes[attr]; + } + } + document.body.appendChild(image) +} + +function decodeImageData(rgba) { + var rgb = new Uint8ClampedArray(rgba.length); + + // RGBA -> RGB. + var rgb_length = 0; + for (var i = 0; i < rgba.length; ++i) { + // Skip alpha component. + if (i % 4 == 3) + continue; + + // Zero is the string terminator. + if (rgba[i] == 0) + break; + + rgb[rgb_length++] = rgba[i]; + } + + // Remove trailing nulls from data. + rgb = rgb.subarray(0, rgb_length); + var string_data = (new TextDecoder("ascii")).decode(rgb); + + return JSON.parse(string_data); +} + +function decodeImage(url, callback, referrer_policy) { + loadImage(url, function(img) { + var canvas = document.createElement("canvas"); + var context = canvas.getContext('2d'); + context.drawImage(img, 0, 0); + var imgData = context.getImageData(0, 0, img.clientWidth, img.clientHeight); + callback(decodeImageData(imgData.data)) + }, referrer_policy); +} + +function normalizePort(targetPort) { + var defaultPorts = [80, 443]; + var isDefaultPortForProtocol = (defaultPorts.indexOf(targetPort) >= 0); + + return (targetPort == "" || isDefaultPortForProtocol) ? + "" : ":" + targetPort; +} + +function wrapResult(url, server_data) { + return { + location: url, + referrer: server_data.headers.referer, + headers: server_data.headers + } +} + +function queryIframe(url, callback, referrer_policy) { + var iframe = appendIframeToBody(url, referrer_policy); + var listener = function(event) { + if (event.source != iframe.contentWindow) + return; + + callback(event.data, url); + window.removeEventListener("message", listener); + } + window.addEventListener("message", listener); +} + +function queryImage(url, callback, referrer_policy) { + decodeImage(url, function(server_data) { + callback(wrapResult(url, server_data), url); + }, referrer_policy) +} + +function queryXhr(url, callback) { + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, true); + xhr.onreadystatechange = function(e) { + if (this.readyState == 4 && this.status == 200) { + var server_data = JSON.parse(this.responseText); + callback(wrapResult(url, server_data), url); + } + }; + xhr.send(); +} + +function queryWorker(url, callback) { + var worker = new Worker(url); + worker.onmessage = function(event) { + var server_data = event.data; + callback(wrapResult(url, server_data), url); + }; +} + +function queryFetch(url, callback) { + fetch(url).then(function(response) { + response.json().then(function(server_data) { + callback(wrapResult(url, server_data), url); + }); + } + ); +} + +function queryNavigable(element, url, callback, attributes) { + var navigable = element + navigable.href = url; + navigable.target = "helper-iframe"; + + var helperIframe = document.createElement("iframe") + helperIframe.name = "helper-iframe" + document.body.appendChild(helperIframe) + + // Extend element with attributes. (E.g. "referrer_policy" or "rel") + if (attributes) { + for (var attr in attributes) { + navigable[attr] = attributes[attr]; + } + } + + var listener = function(event) { + if (event.source != helperIframe.contentWindow) + return; + + callback(event.data, url); + window.removeEventListener("message", listener); + } + window.addEventListener("message", listener); + + navigable.click(); +} + +function queryLink(url, callback, referrer_policy) { + var a = document.createElement("a"); + a.innerHTML = "Link to subresource"; + document.body.appendChild(a); + queryNavigable(a, url, callback, referrer_policy) +} + +function queryAreaLink(url, callback, referrer_policy) { + var area = document.createElement("area"); + // TODO(kristijanburnik): Append to map and add image. + document.body.appendChild(area); + queryNavigable(area, url, callback, referrer_policy) +} + +function queryScript(url, callback) { + var script = document.createElement("script"); + script.src = url; + + var listener = function(event) { + var server_data = event.data; + callback(wrapResult(url, server_data), url); + window.removeEventListener("message", listener); + } + window.addEventListener("message", listener); + + document.body.appendChild(script); +} + + // SanityChecker does nothing in release mode. +function SanityChecker() {} +SanityChecker.prototype.checkScenario = function() {}; +SanityChecker.prototype.checkSubresourceResult = function() {}; + +// TODO(kristijanburnik): document.origin is supported since Chrome 41, +// other browsers still don't support it. Remove once they do. +document.origin = document.origin || (location.protocol + "//" + location.host); diff --git a/testing/web-platform/tests/referrer-policy/generic/referrer-policy-test-case.js b/testing/web-platform/tests/referrer-policy/generic/referrer-policy-test-case.js new file mode 100644 index 000000000..c4cf96fb0 --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/referrer-policy-test-case.js @@ -0,0 +1,125 @@ +function ReferrerPolicyTestCase(scenario, testDescription, sanityChecker) { + // Pass and skip rest of the test if browser does not support fetch. + if (scenario.subresource == "fetch-request" && !window.fetch) { + // TODO(kristijanburnik): This should be refactored. + return { + start: function() { + test(function() { assert_true(true); }, + "[ReferrerPolicyTestCase] Skipping test: Fetch is not supported."); + } + }; + } + + // This check is A NOOP in release. + sanityChecker.checkScenario(scenario); + + var subresourceInvoker = { + "a-tag": queryLink, + "area-tag": queryAreaLink, + "fetch-request": queryFetch, + "iframe-tag": queryIframe, + "img-tag": queryImage, + "script-tag": queryScript, + "worker-request": queryWorker, + "xhr-request": queryXhr + }; + + var referrerUrlResolver = { + "omitted": function() { + return undefined; + }, + "origin": function() { + return document.origin + "/"; + }, + "stripped-referrer": function() { + return stripUrlForUseAsReferrer(location.toString()); + } + }; + + var t = { + _scenario: scenario, + _testDescription: testDescription, + _subresourceUrl: null, + _expectedReferrerUrl: null, + _constructSubresourceUrl: function() { + // TODO(kristijanburnik): We should assert that these two domains are + // different. E.g. If someone runs the tets over www, this would fail. + var domainForOrigin = { + "cross-origin":"{{domains[www1]}}", + "same-origin": location.hostname + }; + + // Values obtained and replaced by the wptserve pipeline: + // http://wptserve.readthedocs.org/en/latest/pipes.html#built-in-pipes + var portForProtocol = { + "http": parseInt("{{ports[http][0]}}"), + "https": parseInt("{{ports[https][0]}}") + } + + var targetPort = portForProtocol[t._scenario.target_protocol]; + + t._subresourceUrl = t._scenario.target_protocol + "://" + + domainForOrigin[t._scenario.origin] + + normalizePort(targetPort) + + t._scenario["subresource_path"] + + "?redirection=" + t._scenario["redirection"] + + "&cache_destroyer=" + (new Date()).getTime(); + }, + + _constructExpectedReferrerUrl: function() { + t._expectedReferrerUrl = referrerUrlResolver[t._scenario.referrer_url](); + }, + + _invokeSubresource: function(callback) { + var invoker = subresourceInvoker[t._scenario.subresource]; + + // Depending on the delivery method, extend the subresource element with + // these attributes. + var elementAttributesForDeliveryMethod = { + "attr-referrer": {referrerPolicy: t._scenario.referrer_policy}, + "rel-noreferrer": {rel: "noreferrer"} + }; + + var delivery_method = t._scenario.delivery_method; + + if (delivery_method in elementAttributesForDeliveryMethod) { + invoker(t._subresourceUrl, + callback, + elementAttributesForDeliveryMethod[delivery_method]); + } else { + invoker(t._subresourceUrl, callback); + } + + }, + + start: function() { + t._constructSubresourceUrl(); + t._constructExpectedReferrerUrl(); + + var test = async_test(t._testDescription); + + t._invokeSubresource(function(result) { + // Check if the result is in valid format. NOOP in release. + sanityChecker.checkSubresourceResult( + test, t._scenario, t._subresourceUrl, result); + + // Check the reported URL. + test.step(function() { + assert_equals(result.referrer, + t._expectedReferrerUrl, + "Reported Referrer URL is '" + + t._scenario.referrer_url + "'."); + assert_equals(result.headers.referer, + t._expectedReferrerUrl, + "Reported Referrer URL from HTTP header is '" + + t._expectedReferrerUrl + "'"); + }, "Reported Referrer URL is as expected: " + t._scenario.referrer_url); + + test.done(); + }) + + } + } + + return t; +} diff --git a/testing/web-platform/tests/referrer-policy/generic/sanity-checker.js b/testing/web-platform/tests/referrer-policy/generic/sanity-checker.js new file mode 100644 index 000000000..e0714885f --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/sanity-checker.js @@ -0,0 +1,52 @@ +// The SanityChecker is used in debug mode to identify problems with the +// structure of the testsuite. In release mode it is mocked out to do nothing. + +function SanityChecker() {} + +SanityChecker.prototype.checkScenario = function(scenario) { + // Check if scenario is valid. + // TODO(kristijanburnik): Move to a sanity-checks.js for debug mode only. + test(function() { + + // We extend the exsiting test_expansion_schema not to kill performance by + // copying. + var expectedFields = SPEC_JSON["test_expansion_schema"]; + expectedFields["referrer_policy"] = SPEC_JSON["referrer_policy_schema"]; + + assert_own_property(scenario, "subresource_path", + "Scenario has the path to the subresource."); + + for (var field in expectedFields) { + assert_own_property(scenario, field, + "The scenario contains field " + field) + assert_in_array(scenario[field], expectedFields[field], + "Scenario's " + field + " is one of: " + + expectedFields[field].join(", ")) + "." + } + + // Check if the protocol is matched. + assert_equals(scenario["source_protocol"] + ":", location.protocol, + "Protocol of the test page should match the scenario.") + + }, "[ReferrerPolicyTestCase] The test scenario is valid."); +} + +SanityChecker.prototype.checkSubresourceResult = function(test, + scenario, + subresourceUrl, + result) { + test.step(function() { + assert_equals(Object.keys(result).length, 3); + assert_own_property(result, "location"); + assert_own_property(result, "referrer"); + assert_own_property(result, "headers"); + + // Skip location check for scripts. + if (scenario.subresource == "script-tag") + return; + + // Sanity check: location of sub-resource matches reported location. + assert_equals(result.location, subresourceUrl, + "Subresource reported location."); + }, "Running a valid test scenario."); +}; diff --git a/testing/web-platform/tests/referrer-policy/generic/subresource-test/area-navigate.html b/testing/web-platform/tests/referrer-policy/generic/subresource-test/area-navigate.html new file mode 100644 index 000000000..bca7e479f --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/subresource-test/area-navigate.html @@ -0,0 +1,39 @@ +<!DOCTYPE html> +<!-- TODO(kristijanburnik): Remove subres. duplication. Reuse a template. --> +<html> + <head> + <title>Area Link messaging - cross-origin Area Link navigation</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <!-- Common global functions for referrer-policy tests. --> + <script src="/referrer-policy/generic/common.js"></script> + </head> + <body> + <h1>Area Link messaging - cross-origin Area Link navigation</h1> + <p>If you can read JSON encoded HTTP request headers of the Area link below, + the messaging works as expected.</p> + + <pre id="received_message">Running...</pre> + + <script> + var messaging_test = async_test("Area is responding with HTTP headers"); + var urlPath = '/referrer-policy/generic/subresource/document.py'; + var url = location.protocol + "//www1." + location.hostname + ":" + location.port + + urlPath; + queryAreaLink(url, function(message) { + var pre = document.getElementById('received_message') + var headers = message.headers; + pre.innerHTML = ""; + pre.innerHTML += url + ":\n\n"; + pre.innerHTML += JSON.stringify(headers, null, 2) + "\n\n" + messaging_test.step(function() { + assert_own_property(headers, "host") + assert_own_property(headers, "connection") + }); + messaging_test.done(); + }); + </script> + + <div id="log"></div> + </body> +</html> diff --git a/testing/web-platform/tests/referrer-policy/generic/subresource-test/attr-referrer-invalid-value.html b/testing/web-platform/tests/referrer-policy/generic/subresource-test/attr-referrer-invalid-value.html new file mode 100644 index 000000000..9bc74f54a --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/subresource-test/attr-referrer-invalid-value.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<html> + <head> + <title>Invalid referrerPolicy attribute value</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <h1>Invalid referrerPolicy attribute value</h1> + <pre>Running...</pre> + + <script> + test(function () { + var elements = ["iframe", "img", "a", "area", "link"]; + for (var i = 0; i < elements.length; i++) { + var elem = document.createElement(elements[i]); + elem.referrerPolicy = "unsafe-url"; + assert_equals(elem.referrerPolicy, "unsafe-url"); + elem.referrerPolicy = "not-valid-value"; + assert_equals(elem.referrerPolicy, ""); + } + }, "Invalid referrerpolicy values not reflected"); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/referrer-policy/generic/subresource-test/fetch-messaging.html b/testing/web-platform/tests/referrer-policy/generic/subresource-test/fetch-messaging.html new file mode 100644 index 000000000..046b29e9a --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/subresource-test/fetch-messaging.html @@ -0,0 +1,48 @@ +<!DOCTYPE html> +<!-- TODO(kristijanburnik): Remove subres. duplication. Reuse a template. --> +<html> + <head> + <title>Fetch messaging - same-origin Fetch request</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <!-- Common global functions for referrer-policy tests. --> + <script src="/referrer-policy/generic/common.js"></script> + </head> + <body> + <h1>Fetch messaging - same-origin Fetch request</h1> + <p>If you can read JSON encoded HTTP request headers of the Fetch below, + the messaging works as expected.</p> + + <pre id="received_message">Running...</pre> + + <script> + test(function() { + assert_true(!!window.fetch, "Fetch is not supported by this browser."); + }, "Fetch is supported by the browser."); + + (function() { + if (!window.fetch) + return; + + var fetch_test = async_test("Fetch is responding with HTTP headers"); + var urlPath = '/referrer-policy/generic/subresource/xhr.py'; + var url = location.protocol + "//" + location.hostname + ":" + + location.port + urlPath; + queryFetch(url, function(message) { + var pre = document.getElementById('received_message') + var headers = message.headers; + pre.innerHTML = ""; + pre.innerHTML += url + ":\n\n"; + pre.innerHTML += JSON.stringify(headers, null, 2) + "\n\n"; + fetch_test.step(function() { + assert_own_property(headers, "host") + assert_own_property(headers, "connection") + }); + fetch_test.done(); + }); + })(); + </script> + + <div id="log"></div> + </body> +</html> diff --git a/testing/web-platform/tests/referrer-policy/generic/subresource-test/iframe-messaging.html b/testing/web-platform/tests/referrer-policy/generic/subresource-test/iframe-messaging.html new file mode 100644 index 000000000..a3e55707c --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/subresource-test/iframe-messaging.html @@ -0,0 +1,39 @@ +<!DOCTYPE html> +<!-- TODO(kristijanburnik): Remove subres. duplication. Reuse a template. --> +<html> + <head> + <title>Iframe messaging - cross-origin iframe request</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <!-- Common global functions for referrer-policy tests. --> + <script src="/referrer-policy/generic/common.js"></script> + </head> + <body> + <h1>Iframe messaging - cross-origin iframe request</h1> + <p>If you can read JSON encoded HTTP request headers of the iframe below, + the messaging works as expected.</p> + + <pre id="received_message">Running...</pre> + + <script> + var messaging_test = async_test("Iframe is responding with HTTP headers"); + var urlPath = '/referrer-policy/generic/subresource/document.py'; + var url = location.protocol + "//www1." + location.hostname + ":" + location.port + + urlPath; + queryIframe(url, function(message) { + var pre = document.getElementById('received_message') + var headers = message.headers; + pre.innerHTML = ""; + pre.innerHTML += url + ":\n\n"; + pre.innerHTML += JSON.stringify(headers, null, 2) + "\n\n" + messaging_test.step(function() { + assert_own_property(headers, "host") + assert_own_property(headers, "connection") + }); + messaging_test.done(); + }); + </script> + + <div id="log"></div> + </body> +</html> diff --git a/testing/web-platform/tests/referrer-policy/generic/subresource-test/image-decoding.html b/testing/web-platform/tests/referrer-policy/generic/subresource-test/image-decoding.html new file mode 100644 index 000000000..083fb829a --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/subresource-test/image-decoding.html @@ -0,0 +1,39 @@ +<!DOCTYPE html> +<!-- TODO(kristijanburnik): Remove subres. duplication. Reuse a template. --> +<html> + <head> + <title>Image decoding - cross-origin image request</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <!-- Common global functions for referrer-policy tests. --> + <script src="/referrer-policy/generic/common.js"></script> + </head> + <body> + <h1>Image decoding - cross-origin image request</h1> + <p>If you can read JSON encoded HTTP headers of the image below, + the decoding works as expected.</p> + + <pre id="received_message">Running...</pre> + + <script> + var messaging_test = async_test("Image is encoding headers as JSON."); + var urlPath = '/referrer-policy/generic/subresource/image.py'; + var url = location.protocol + "//www1." + location.hostname + ":" + location.port + + urlPath; + queryImage(url, function(message) { + var pre = document.getElementById('received_message') + var headers = message.headers; + pre.innerHTML = ""; + pre.innerHTML += url + ":\n\n"; + pre.innerHTML += JSON.stringify(headers, null, 2) + "\n\n" + messaging_test.step(function() { + assert_own_property(headers, "host") + assert_own_property(headers, "connection") + }); + messaging_test.done(); + }); + </script> + + <div id="log"></div> + </body> +</html> diff --git a/testing/web-platform/tests/referrer-policy/generic/subresource-test/link-navigate.html b/testing/web-platform/tests/referrer-policy/generic/subresource-test/link-navigate.html new file mode 100644 index 000000000..45e502004 --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/subresource-test/link-navigate.html @@ -0,0 +1,39 @@ +<!DOCTYPE html> +<!-- TODO(kristijanburnik): Remove subres. duplication. Reuse a template. --> +<html> + <head> + <title>Link messaging - cross-origin Link navigation</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <!-- Common global functions for referrer-policy tests. --> + <script src="/referrer-policy/generic/common.js"></script> + </head> + <body> + <h1>Link messaging - cross-origin Link navigation</h1> + <p>If you can read JSON encoded HTTP request headers of the Link below, + the messaging works as expected.</p> + + <pre id="received_message">Running...</pre> + + <script> + var messaging_test = async_test("Link is responding with HTTP headers"); + var urlPath = '/referrer-policy/generic/subresource/document.py'; + var url = location.protocol + "//www1." + location.hostname + ":" + location.port + + urlPath; + queryLink(url, function(message) { + var pre = document.getElementById('received_message') + var headers = message.headers; + pre.innerHTML = ""; + pre.innerHTML += url + ":\n\n"; + pre.innerHTML += JSON.stringify(headers, null, 2) + "\n\n" + messaging_test.step(function() { + assert_own_property(headers, "host") + assert_own_property(headers, "connection") + }); + messaging_test.done(); + }); + </script> + + <div id="log"></div> + </body> +</html> diff --git a/testing/web-platform/tests/referrer-policy/generic/subresource-test/script-messaging.html b/testing/web-platform/tests/referrer-policy/generic/subresource-test/script-messaging.html new file mode 100644 index 000000000..09c5db619 --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/subresource-test/script-messaging.html @@ -0,0 +1,39 @@ +<!DOCTYPE html> +<!-- TODO(kristijanburnik): Remove subres. duplication. Reuse a template. --> +<html> + <head> + <title>Script messaging - cross-origin Script request</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <!-- Common global functions for referrer-policy tests. --> + <script src="/referrer-policy/generic/common.js"></script> + </head> + <body> + <h1>Script messaging - cross-origin Script request</h1> + <p>If you can read JSON encoded HTTP request headers of the Script below, + the messaging works as expected.</p> + + <pre id="received_message">Running...</pre> + + <script> + var messaging_test = async_test("Script is responding with HTTP headers"); + var urlPath = '/referrer-policy/generic/subresource/script.py'; + var url = location.protocol + "//www1." + location.hostname + ":" + location.port + + urlPath; + queryScript(url, function(message) { + var pre = document.getElementById('received_message') + var headers = message.headers; + pre.innerHTML = ""; + pre.innerHTML += url + ":\n\n"; + pre.innerHTML += JSON.stringify(headers, null, 2) + "\n\n" + messaging_test.step(function() { + assert_own_property(headers, "host") + assert_own_property(headers, "connection") + }); + messaging_test.done(); + }); + </script> + + <div id="log"></div> + </body> +</html> diff --git a/testing/web-platform/tests/referrer-policy/generic/subresource-test/worker-messaging.html b/testing/web-platform/tests/referrer-policy/generic/subresource-test/worker-messaging.html new file mode 100644 index 000000000..6d34366b9 --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/subresource-test/worker-messaging.html @@ -0,0 +1,39 @@ +<!DOCTYPE html> +<!-- TODO(kristijanburnik): Remove subres. duplication. Reuse a template. --> +<html> + <head> + <title>Worker messaging - same-origin Worker request</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <!-- Common global functions for referrer-policy tests. --> + <script src="/referrer-policy/generic/common.js"></script> + </head> + <body> + <h1>Worker messaging - same-origin Worker request</h1> + <p>If you can read JSON encoded HTTP request headers of the Worker below, + the messaging works as expected.</p> + + <pre id="received_message">Running...</pre> + + <script> + var messaging_test = async_test("Worker is responding with HTTP headers"); + var urlPath = '/referrer-policy/generic/subresource/worker.py'; + var url = location.protocol + "//" + location.hostname + ":" + + location.port + urlPath; + queryWorker(url, function(message) { + var pre = document.getElementById('received_message') + var headers = message.headers; + pre.innerHTML = ""; + pre.innerHTML += url + ":\n\n"; + pre.innerHTML += JSON.stringify(headers, null, 2) + "\n\n" + messaging_test.step(function() { + assert_own_property(headers, "host") + assert_own_property(headers, "connection") + }); + messaging_test.done(); + }); + </script> + + <div id="log"></div> + </body> +</html> diff --git a/testing/web-platform/tests/referrer-policy/generic/subresource-test/xhr-messaging.html b/testing/web-platform/tests/referrer-policy/generic/subresource-test/xhr-messaging.html new file mode 100644 index 000000000..09f691400 --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/subresource-test/xhr-messaging.html @@ -0,0 +1,39 @@ +<!DOCTYPE html> +<!-- TODO(kristijanburnik): Remove subres. duplication. Reuse a template. --> +<html> + <head> + <title>XHR messaging - cross-origin XHR request</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <!-- Common global functions for referrer-policy tests. --> + <script src="/referrer-policy/generic/common.js"></script> + </head> + <body> + <h1>XHR messaging - cross-origin XHR request</h1> + <p>If you can read JSON encoded HTTP request headers of the XHR below, + the messaging works as expected.</p> + + <pre id="received_message">Running...</pre> + + <script> + var messaging_test = async_test("XHR is responding with HTTP headers"); + var urlPath = '/referrer-policy/generic/subresource/xhr.py'; + var url = location.protocol + "//www1." + location.hostname + ":" + location.port + + urlPath; + queryXhr(url, function(message) { + var pre = document.getElementById('received_message') + var headers = message.headers; + pre.innerHTML = ""; + pre.innerHTML += url + ":\n\n"; + pre.innerHTML += JSON.stringify(headers, null, 2) + "\n\n" + messaging_test.step(function() { + assert_own_property(headers, "host") + assert_own_property(headers, "connection") + }); + messaging_test.done(); + }); + </script> + + <div id="log"></div> + </body> +</html> diff --git a/testing/web-platform/tests/referrer-policy/generic/subresource/__init__.py b/testing/web-platform/tests/referrer-policy/generic/subresource/__init__.py new file mode 100755 index 000000000..e69de29bb --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/subresource/__init__.py diff --git a/testing/web-platform/tests/referrer-policy/generic/subresource/document.py b/testing/web-platform/tests/referrer-policy/generic/subresource/document.py new file mode 100644 index 000000000..b2d6c4dfa --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/subresource/document.py @@ -0,0 +1,12 @@ +import os, json, sys +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +import subresource + +def generate_payload(server_data): + return subresource.get_template("document.html.template") % server_data + +def main(request, response): + subresource.respond(request, + response, + payload_generator = generate_payload) diff --git a/testing/web-platform/tests/referrer-policy/generic/subresource/image.py b/testing/web-platform/tests/referrer-policy/generic/subresource/image.py new file mode 100644 index 000000000..b6306181e --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/subresource/image.py @@ -0,0 +1,100 @@ +import os, sys, array, json, math, StringIO +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +import subresource + +class Image: + """This class partially implements the interface of the PIL.Image.Image. + One day in the future WPT might support the PIL module or another imaging + library, so this hacky BMP implementation will no longer be required. + """ + def __init__(self, width, height): + self.width = width + self.height = height + self.img = bytearray([0 for i in range(3 * width * height)]) + + @staticmethod + def new(mode, size, color=0): + return Image(size[0], size[1]) + + def _int_to_bytes(self, number): + packed_bytes = [0, 0, 0, 0] + for i in range(4): + packed_bytes[i] = number & 0xFF + number >>= 8 + + return packed_bytes + + def putdata(self, color_data): + for y in range(self.height): + for x in range(self.width): + i = x + y * self.width + if i > len(color_data) - 1: + return + + self.img[i * 3: i * 3 + 3] = color_data[i][::-1] + + def save(self, f, type): + assert type == "BMP" + # 54 bytes of preambule + image color data. + filesize = 54 + 3 * self.width * self.height; + # 14 bytes of header. + bmpfileheader = bytearray(['B', 'M'] + self._int_to_bytes(filesize) + + [0, 0, 0, 0, 54, 0, 0, 0]) + # 40 bytes of info. + bmpinfoheader = bytearray([40, 0, 0, 0] + + self._int_to_bytes(self.width) + + self._int_to_bytes(self.height) + + [1, 0, 24] + (25 * [0])) + + padlength = (4 - (self.width * 3) % 4) % 4 + bmppad = bytearray([0, 0, 0]); + padding = bmppad[0 : padlength] + + f.write(bmpfileheader) + f.write(bmpinfoheader) + + for i in range(self.height): + offset = self.width * (self.height - i - 1) * 3 + f.write(self.img[offset : offset + 3 * self.width]) + f.write(padding) + +def encode_string_as_bmp_image(string_data): + data_bytes = array.array("B", string_data) + num_bytes = len(data_bytes) + + # Convert data bytes to color data (RGB). + color_data = [] + num_components = 3 + rgb = [0] * num_components + i = 0 + for byte in data_bytes: + component_index = i % num_components + rgb[component_index] = byte + if component_index == (num_components - 1) or i == (num_bytes - 1): + color_data.append(tuple(rgb)) + rgb = [0] * num_components + i += 1 + + # Render image. + num_pixels = len(color_data) + sqrt = int(math.ceil(math.sqrt(num_pixels))) + img = Image.new("RGB", (sqrt, sqrt), "black") + img.putdata(color_data) + + # Flush image to string. + f = StringIO.StringIO() + img.save(f, "BMP") + f.seek(0) + + return f.read() + +def generate_payload(server_data): + data = ('{"headers": %(headers)s}') % server_data + return encode_string_as_bmp_image(data) + +def main(request, response): + subresource.respond(request, + response, + payload_generator = generate_payload, + content_type = "image/bmp", + access_control_allow_origin = "*") diff --git a/testing/web-platform/tests/referrer-policy/generic/subresource/script.py b/testing/web-platform/tests/referrer-policy/generic/subresource/script.py new file mode 100644 index 000000000..efa1a955d --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/subresource/script.py @@ -0,0 +1,13 @@ +import os, sys, json +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +import subresource + +def generate_payload(server_data): + return subresource.get_template("script.js.template") % server_data + +def main(request, response): + subresource.respond(request, + response, + payload_generator = generate_payload, + content_type = "application/javascript") + diff --git a/testing/web-platform/tests/referrer-policy/generic/subresource/subresource.py b/testing/web-platform/tests/referrer-policy/generic/subresource/subresource.py new file mode 100644 index 000000000..7571b32d0 --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/subresource/subresource.py @@ -0,0 +1,94 @@ +import os, sys, json, urlparse, urllib + +def get_template(template_basename): + script_directory = os.path.dirname(os.path.abspath(__file__)) + template_directory = os.path.abspath(os.path.join(script_directory, + "..", + "template")) + template_filename = os.path.join(template_directory, template_basename); + + with open(template_filename, "r") as f: + return f.read() + +# TODO(kristijanburnik): subdomain_prefix is a hardcoded value aligned with +# referrer-policy-test-case.js. The prefix should be configured in one place. +def get_swapped_origin_netloc(netloc, subdomain_prefix = "www1."): + if netloc.startswith(subdomain_prefix): + return netloc[len(subdomain_prefix):] + else: + return subdomain_prefix + netloc + +def create_redirect_url(request, cross_origin = False): + parsed = urlparse.urlsplit(request.url) + destination_netloc = parsed.netloc + if cross_origin: + destination_netloc = get_swapped_origin_netloc(parsed.netloc) + + destination_url = urlparse.urlunsplit(urlparse.SplitResult( + scheme = parsed.scheme, + netloc = destination_netloc, + path = parsed.path, + query = None, + fragment = None)) + + return destination_url + + +def redirect(url, response): + response.add_required_headers = False + response.writer.write_status(301) + response.writer.write_header("access-control-allow-origin", "*") + response.writer.write_header("location", url) + response.writer.end_headers() + response.writer.write("") + + +def preprocess_redirection(request, response): + if "redirection" not in request.GET: + return False + + redirection = request.GET["redirection"] + + if redirection == "no-redirect": + return False + elif redirection == "keep-origin-redirect": + redirect_url = create_redirect_url(request, cross_origin = False) + elif redirection == "swap-origin-redirect": + redirect_url = create_redirect_url(request, cross_origin = True) + else: + raise ValueError("Invalid redirection type '%s'" % redirection) + + redirect(redirect_url, response) + return True + + +def __noop(request, response): + return "" + + +def respond(request, + response, + status_code = 200, + content_type = "text/html", + payload_generator = __noop, + cache_control = "no-cache; must-revalidate", + access_control_allow_origin = "*"): + if preprocess_redirection(request, response): + return + + response.add_required_headers = False + response.writer.write_status(status_code) + + if access_control_allow_origin != None: + response.writer.write_header("access-control-allow-origin", + access_control_allow_origin) + response.writer.write_header("content-type", content_type) + response.writer.write_header("cache-control", cache_control) + response.writer.end_headers() + + server_data = {"headers": json.dumps(request.headers, indent = 4)} + + payload = payload_generator(server_data) + response.writer.write(payload) + + diff --git a/testing/web-platform/tests/referrer-policy/generic/subresource/worker.py b/testing/web-platform/tests/referrer-policy/generic/subresource/worker.py new file mode 100644 index 000000000..895bc0d84 --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/subresource/worker.py @@ -0,0 +1,12 @@ +import os, sys, json +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +import subresource + +def generate_payload(server_data): + return subresource.get_template("worker.js.template") % server_data + +def main(request, response): + subresource.respond(request, + response, + payload_generator = generate_payload, + content_type = "application/javascript") diff --git a/testing/web-platform/tests/referrer-policy/generic/subresource/xhr.py b/testing/web-platform/tests/referrer-policy/generic/subresource/xhr.py new file mode 100755 index 000000000..45f38159c --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/subresource/xhr.py @@ -0,0 +1,15 @@ +import os, sys, json +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +import subresource + +def generate_payload(server_data): + data = ('{"headers": %(headers)s}') % server_data + return data + +def main(request, response): + subresource.respond(request, + response, + payload_generator = generate_payload, + access_control_allow_origin = "*", + content_type = "application/json") + diff --git a/testing/web-platform/tests/referrer-policy/generic/template/disclaimer.template b/testing/web-platform/tests/referrer-policy/generic/template/disclaimer.template new file mode 100644 index 000000000..66c43ed6f --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/template/disclaimer.template @@ -0,0 +1 @@ +<!-- DO NOT EDIT! Generated by %(generating_script_filename)s using %(html_template_filename)s. --> diff --git a/testing/web-platform/tests/referrer-policy/generic/template/document.html.template b/testing/web-platform/tests/referrer-policy/generic/template/document.html.template new file mode 100644 index 000000000..141711c14 --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/template/document.html.template @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<html> + <head> + <title>This page reports back it's request details to the parent frame</title> + </head> + <body> + <script> + var result = { + location: document.location.toString(), + referrer: document.referrer.length > 0 ? document.referrer : undefined, + headers: %(headers)s + }; + parent.postMessage(result, "*"); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/referrer-policy/generic/template/script.js.template b/testing/web-platform/tests/referrer-policy/generic/template/script.js.template new file mode 100644 index 000000000..e2edf2181 --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/template/script.js.template @@ -0,0 +1,3 @@ +postMessage({ + "headers": %(headers)s +}, "*"); diff --git a/testing/web-platform/tests/referrer-policy/generic/template/spec_json.js.template b/testing/web-platform/tests/referrer-policy/generic/template/spec_json.js.template new file mode 100644 index 000000000..e4cbd0342 --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/template/spec_json.js.template @@ -0,0 +1 @@ +var SPEC_JSON = %(spec_json)s; diff --git a/testing/web-platform/tests/referrer-policy/generic/template/test.debug.html.template b/testing/web-platform/tests/referrer-policy/generic/template/test.debug.html.template new file mode 100644 index 000000000..0faf63bdd --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/template/test.debug.html.template @@ -0,0 +1,70 @@ +<!DOCTYPE html> +%(generated_disclaimer)s +<html> + <head> + <title>Referrer-Policy: %(spec_title)s</title>%(meta_delivery_method)s + <meta name="description" content="%(spec_description)s"> + <meta name="assert" content="%(test_description)s"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <!-- Common global functions for referrer-policy tests. --> + <script src="/referrer-policy/generic/common.js"></script> + <!-- The original specification JSON for validating the scenario. --> + <script src="/referrer-policy/spec_json.js"></script> + <!-- Internal checking of the tests --> + <script src="/referrer-policy/generic/sanity-checker.js"></script> + <!-- Simple wrapper API for all referrer-policy test cases. --> + <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script> + </head> + <body> + <h1>%(spec_title)s</h1> + <h2>%(spec_description)s</h2> + + <p> + <script> + // Show the detailed assertion description of the test. + document.write(document.querySelector("meta[name=assert]").content); + </script> + </p> + + <p>See <a href="%(spec_specification_url)s" target="_blank">specification</a> + details for this test.</p> + + <h3>Scenario outline</h3> + <table> + <tbody> + <tr> + <th>Delivery method</th> + <td>%(delivery_method)s</td> + </tr> + <tr> + <th>Redirection</th> + <td>%(redirection)s</td> + </tr> + <tr> + <th>Origin transition</th> + <td>%(origin)s</td> + </tr> + <tr> + <th>Protocol transition</th> + <td>from %(source_protocol)s to %(target_protocol)s</td> + </tr> + <tr> + <th>Subresource type</th> + <td>%(subresource)s</td> + </tr> + <tr> + <td colspan="2"><hr></td> + </tr> + <tr> + <th>Expected result</th> + <td>Referrer URL should be <strong>%(referrer_url)s</strong></td> + </tr> + <tbody> + </table> + + <script>%(test_js)s</script> + + <div id="log"></div> + </body> +</html> diff --git a/testing/web-platform/tests/referrer-policy/generic/template/test.js.template b/testing/web-platform/tests/referrer-policy/generic/template/test.js.template new file mode 100644 index 000000000..4b01d4d11 --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/template/test.js.template @@ -0,0 +1,15 @@ +ReferrerPolicyTestCase( + { + "referrer_policy": %(referrer_policy_json)s, + "delivery_method": "%(delivery_method)s", + "redirection": "%(redirection)s", + "origin": "%(origin)s", + "source_protocol": "%(source_protocol)s", + "target_protocol": "%(target_protocol)s", + "subresource": "%(subresource)s", + "subresource_path": "%(subresource_path)s", + "referrer_url": "%(referrer_url)s" + }, + document.querySelector("meta[name=assert]").content, + new SanityChecker() +).start(); diff --git a/testing/web-platform/tests/referrer-policy/generic/template/test.release.html.template b/testing/web-platform/tests/referrer-policy/generic/template/test.release.html.template new file mode 100644 index 000000000..0d63fd68a --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/template/test.release.html.template @@ -0,0 +1,20 @@ +<!DOCTYPE html> +%(generated_disclaimer)s +<html> + <head> + <title>Referrer-Policy: %(spec_title)s</title> + <meta name="description" content="%(spec_description)s">%(meta_delivery_method)s + <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org"> + <link rel="help" href="%(spec_specification_url)s"> + <meta name="assert" content="%(test_description)s"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <!-- TODO(kristijanburnik): Minify and merge both: --> + <script src="/referrer-policy/generic/common.js"></script> + <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script> + </head> + <body> + <script>%(test_js)s</script> + <div id="log"></div> + </body> +</html> diff --git a/testing/web-platform/tests/referrer-policy/generic/template/test_description.template b/testing/web-platform/tests/referrer-policy/generic/template/test_description.template new file mode 100644 index 000000000..fbc80bb25 --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/template/test_description.template @@ -0,0 +1,5 @@ +The referrer URL is %(referrer_url)s when a +document served over %(source_protocol)s requires an %(target_protocol)s +sub-resource via %(subresource)s using the %(delivery_method)s +delivery method with %(redirection)s and when +the target request is %(origin)s. diff --git a/testing/web-platform/tests/referrer-policy/generic/template/worker.js.template b/testing/web-platform/tests/referrer-policy/generic/template/worker.js.template new file mode 100644 index 000000000..817dd8c87 --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/template/worker.js.template @@ -0,0 +1,3 @@ +postMessage({ + "headers": %(headers)s +}); diff --git a/testing/web-platform/tests/referrer-policy/generic/tools/__init__.py b/testing/web-platform/tests/referrer-policy/generic/tools/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/tools/__init__.py diff --git a/testing/web-platform/tests/referrer-policy/generic/tools/clean.py b/testing/web-platform/tests/referrer-policy/generic/tools/clean.py new file mode 100755 index 000000000..715e1d6ae --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/tools/clean.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python + +import os, json +from common_paths import * +import spec_validator + +def rmtree(top): + top = os.path.abspath(top) + assert top != os.path.expanduser("~") + assert len(top) > len(os.path.expanduser("~")) + assert "web-platform-tests" in top + assert "referrer-policy" in top + + for root, dirs, files in os.walk(top, topdown=False): + for name in files: + os.remove(os.path.join(root, name)) + for name in dirs: + os.rmdir(os.path.join(root, name)) + + os.rmdir(top) + +def main(): + spec_json = load_spec_json(); + spec_validator.assert_valid_spec_json(spec_json) + + for spec in spec_json['specification']: + generated_dir = os.path.join(spec_directory, spec["name"]) + if (os.path.isdir(generated_dir)): + rmtree(generated_dir) + + if (os.path.isfile(generated_spec_json_filename)): + os.remove(generated_spec_json_filename) + +if __name__ == '__main__': + main() diff --git a/testing/web-platform/tests/referrer-policy/generic/tools/common_paths.py b/testing/web-platform/tests/referrer-policy/generic/tools/common_paths.py new file mode 100644 index 000000000..dc303f3c1 --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/tools/common_paths.py @@ -0,0 +1,52 @@ +import os, sys, json, re + +script_directory = os.path.dirname(os.path.abspath(__file__)) +generic_directory = os.path.abspath(os.path.join(script_directory, '..')) + +template_directory = os.path.abspath(os.path.join(script_directory, + '..', + 'template')) +spec_directory = os.path.abspath(os.path.join(script_directory, '..', '..')) +test_root_directory = os.path.abspath(os.path.join(script_directory, + '..', '..', '..')) + +spec_filename = os.path.join(spec_directory, "spec.src.json") +generated_spec_json_filename = os.path.join(spec_directory, "spec_json.js") + +selection_pattern = '%(delivery_method)s/' + \ + '%(origin)s/' + \ + '%(source_protocol)s-%(target_protocol)s/' + \ + '%(subresource)s/' + +test_file_path_pattern = '%(spec_name)s/' + selection_pattern + \ + '%(name)s.%(redirection)s.%(source_protocol)s.html' + + +def get_template(basename): + with open(os.path.join(template_directory, basename), "r") as f: + return f.read() + + +def read_nth_line(fp, line_number): + fp.seek(0) + for i, line in enumerate(fp): + if (i + 1) == line_number: + return line + + +def load_spec_json(): + re_error_location = re.compile('line ([0-9]+) column ([0-9]+)') + with open(spec_filename, "r") as f: + try: + spec_json = json.load(f) + except ValueError, ex: + print ex.message + match = re_error_location.search(ex.message) + if match: + line_number, column = int(match.group(1)), int(match.group(2)) + print read_nth_line(f, line_number).rstrip() + print " " * (column - 1) + "^" + + sys.exit(1) + + return spec_json diff --git a/testing/web-platform/tests/referrer-policy/generic/tools/generate.py b/testing/web-platform/tests/referrer-policy/generic/tools/generate.py new file mode 100755 index 000000000..10fc11c4f --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/tools/generate.py @@ -0,0 +1,172 @@ +#!/usr/bin/env python + +import os, sys, json +from common_paths import * +import spec_validator +import argparse + + +def expand_test_expansion_pattern(spec_test_expansion, test_expansion_schema): + expansion = {} + for artifact in spec_test_expansion: + artifact_value = spec_test_expansion[artifact] + if artifact_value == '*': + expansion[artifact] = test_expansion_schema[artifact] + elif isinstance(artifact_value, list): + expansion[artifact] = artifact_value + else: + expansion[artifact] = [artifact_value] + + return expansion + + +def permute_expansion(expansion, selection = {}, artifact_index = 0): + artifact_order = ['delivery_method', 'redirection', 'origin', + 'source_protocol', 'target_protocol', 'subresource', + 'referrer_url', 'name'] + + if artifact_index >= len(artifact_order): + yield selection + return + + artifact_key = artifact_order[artifact_index] + + for artifact_value in expansion[artifact_key]: + selection[artifact_key] = artifact_value + for next_selection in permute_expansion(expansion, + selection, + artifact_index + 1): + yield next_selection + + +def generate_selection(selection, spec, subresource_path, + test_html_template_basename): + selection['spec_name'] = spec['name'] + selection['spec_title'] = spec['title'] + selection['spec_description'] = spec['description'] + selection['spec_specification_url'] = spec['specification_url'] + selection['subresource_path'] = subresource_path + # Oddball: it can be None, so in JS it's null. + selection['referrer_policy_json'] = json.dumps(spec['referrer_policy']) + + test_filename = test_file_path_pattern % selection + test_directory = os.path.dirname(test_filename) + full_path = os.path.join(spec_directory, test_directory) + + test_html_template = get_template(test_html_template_basename) + test_js_template = get_template("test.js.template") + disclaimer_template = get_template('disclaimer.template') + test_description_template = get_template("test_description.template") + + html_template_filename = os.path.join(template_directory, + test_html_template_basename) + generated_disclaimer = disclaimer_template \ + % {'generating_script_filename': os.path.relpath(__file__, + test_root_directory), + 'html_template_filename': os.path.relpath(html_template_filename, + test_root_directory)} + + # Adjust the template for the test invoking JS. Indent it to look nice. + selection['generated_disclaimer'] = generated_disclaimer.rstrip() + test_description_template = \ + test_description_template.rstrip().replace("\n", "\n" + " " * 33) + selection['test_description'] = test_description_template % selection + + # Adjust the template for the test invoking JS. Indent it to look nice. + indent = "\n" + " " * 6; + test_js_template = indent + test_js_template.replace("\n", indent); + selection['test_js'] = test_js_template % selection + + # Directory for the test files. + try: + os.makedirs(full_path) + except: + pass + + selection['meta_delivery_method'] = '' + + if spec['referrer_policy'] != None: + if selection['delivery_method'] == 'meta-referrer': + selection['meta_delivery_method'] = \ + '<meta name="referrer" content="%(referrer_policy)s">' % spec + elif selection['delivery_method'] == 'http-rp': + selection['meta_delivery_method'] = \ + "<!-- No meta: Referrer policy delivered via HTTP headers. -->" + test_headers_filename = test_filename + ".headers" + with open(test_headers_filename, "w") as f: + f.write('Referrer-Policy: ' + \ + '%(referrer_policy)s\n' % spec) + # TODO(kristijanburnik): Limit to WPT origins. + f.write('Access-Control-Allow-Origin: *\n') + elif selection['delivery_method'] == 'attr-referrer': + # attr-referrer is supported by the JS test wrapper. + pass + elif selection['delivery_method'] == 'rel-noreferrer': + # rel=noreferrer is supported by the JS test wrapper. + pass + else: + raise ValueError('Not implemented delivery_method: ' \ + + selection['delivery_method']) + + # Obey the lint and pretty format. + if len(selection['meta_delivery_method']) > 0: + selection['meta_delivery_method'] = "\n " + \ + selection['meta_delivery_method'] + + with open(test_filename, 'w') as f: + f.write(test_html_template % selection) + + +def generate_test_source_files(spec_json, target): + test_expansion_schema = spec_json['test_expansion_schema'] + specification = spec_json['specification'] + + spec_json_js_template = get_template('spec_json.js.template') + with open(generated_spec_json_filename, 'w') as f: + f.write(spec_json_js_template + % {'spec_json': json.dumps(spec_json)}) + + # Choose a debug/release template depending on the target. + html_template = "test.%s.html.template" % target + + # Create list of excluded tests. + exclusion_dict = {} + for excluded_pattern in spec_json['excluded_tests']: + excluded_expansion = \ + expand_test_expansion_pattern(excluded_pattern, + test_expansion_schema) + for excluded_selection in permute_expansion(excluded_expansion): + excluded_selection_path = selection_pattern % excluded_selection + exclusion_dict[excluded_selection_path] = True + + for spec in specification: + for spec_test_expansion in spec['test_expansion']: + expansion = expand_test_expansion_pattern(spec_test_expansion, + test_expansion_schema) + for selection in permute_expansion(expansion): + selection_path = selection_pattern % selection + if not selection_path in exclusion_dict: + subresource_path = \ + spec_json["subresource_path"][selection["subresource"]] + generate_selection(selection, + spec, + subresource_path, + html_template) + else: + print 'Excluding selection:', selection_path + + +def main(target): + spec_json = load_spec_json(); + spec_validator.assert_valid_spec_json(spec_json) + generate_test_source_files(spec_json, target) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Test suite generator utility') + parser.add_argument('-t', '--target', type = str, + choices = ("release", "debug"), default = "release", + help = 'Sets the appropriate template for generating tests') + # TODO(kristijanburnik): Add option for the spec_json file. + args = parser.parse_args() + main(args.target) diff --git a/testing/web-platform/tests/referrer-policy/generic/tools/regenerate b/testing/web-platform/tests/referrer-policy/generic/tools/regenerate new file mode 100755 index 000000000..e6bd63519 --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/tools/regenerate @@ -0,0 +1,3 @@ +#!/bin/bash +DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) +python $DIR/clean.py && python $DIR/generate.py diff --git a/testing/web-platform/tests/referrer-policy/generic/tools/spec_validator.py b/testing/web-platform/tests/referrer-policy/generic/tools/spec_validator.py new file mode 100755 index 000000000..8641bbc1f --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/tools/spec_validator.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python + +import json, sys +from common_paths import * + +def assert_non_empty_string(obj, field): + assert field in obj, 'Missing field "%s"' % field + assert isinstance(obj[field], basestring), \ + 'Field "%s" must be a string' % field + assert len(obj[field]) > 0, 'Field "%s" must not be empty' % field + +def assert_non_empty_list(obj, field): + assert isinstance(obj[field], list), \ + '%s must be a list' % field + assert len(obj[field]) > 0, \ + '%s list must not be empty' % field + +def assert_non_empty_dict(obj, field): + assert isinstance(obj[field], dict), \ + '%s must be a dict' % field + assert len(obj[field]) > 0, \ + '%s dict must not be empty' % field + +def assert_contains(obj, field): + assert field in obj, 'Must contain field "%s"' % field + +def assert_value_from(obj, field, items): + assert obj[field] in items, \ + 'Field "%s" must be from: %s' % (field, str(items)) + +def assert_atom_or_list_items_from(obj, field, items): + if isinstance(obj[field], basestring) or isinstance(obj[field], int): + assert_value_from(obj, field, items) + return + + assert_non_empty_list(obj, field) + for allowed_value in obj[field]: + assert allowed_value != '*', "Wildcard is not supported for lists!" + assert allowed_value in items, \ + 'Field "%s" must be from: %s' % (field, str(items)) + +def assert_contains_only_fields(obj, expected_fields): + for expected_field in expected_fields: + assert_contains(obj, expected_field) + + for actual_field in obj: + assert actual_field in expected_fields, \ + 'Unexpected field "%s".' % actual_field + +def assert_value_unique_in(value, used_values): + assert value not in used_values, 'Duplicate value "%s"!' % str(value) + used_values[value] = True + + +def validate(spec_json, details): + """ Validates the json specification for generating tests. """ + + details['object'] = spec_json + assert_contains_only_fields(spec_json, ["specification", + "referrer_policy_schema", + "test_expansion_schema", + "subresource_path", + "excluded_tests"]) + assert_non_empty_list(spec_json, "specification") + assert_non_empty_list(spec_json, "referrer_policy_schema") + assert_non_empty_dict(spec_json, "test_expansion_schema") + assert_non_empty_list(spec_json, "excluded_tests") + + specification = spec_json['specification'] + referrer_policy_schema = spec_json['referrer_policy_schema'] + test_expansion_schema = spec_json['test_expansion_schema'] + excluded_tests = spec_json['excluded_tests'] + subresource_path = spec_json['subresource_path'] + + valid_test_expansion_fields = ['name'] + test_expansion_schema.keys() + + # Validate each single spec. + for spec in specification: + details['object'] = spec + + # Validate required fields for a single spec. + assert_contains_only_fields(spec, ['name', + 'title', + 'description', + 'referrer_policy', + 'specification_url', + 'test_expansion']) + assert_non_empty_string(spec, 'name') + assert_non_empty_string(spec, 'title') + assert_non_empty_string(spec, 'description') + assert_non_empty_string(spec, 'specification_url') + assert_value_from(spec, 'referrer_policy', referrer_policy_schema) + assert_non_empty_list(spec, 'test_expansion') + + # Validate spec's test expansion. + used_spec_names = {} + + for spec_exp in spec['test_expansion']: + details['object'] = spec_exp + assert_non_empty_string(spec_exp, 'name') + # The name is unique in same expansion group. + assert_value_unique_in((spec_exp['expansion'], spec_exp['name']), + used_spec_names) + assert_contains_only_fields(spec_exp, valid_test_expansion_fields) + + for artifact in test_expansion_schema: + details['test_expansion_field'] = artifact + assert_atom_or_list_items_from( + spec_exp, artifact, ['*'] + test_expansion_schema[artifact]) + del details['test_expansion_field'] + + # Validate the test_expansion schema members. + details['object'] = test_expansion_schema + assert_contains_only_fields(test_expansion_schema, ['expansion', + 'delivery_method', + 'redirection', + 'origin', + 'source_protocol', + 'target_protocol', + 'subresource', + 'referrer_url']) + # Validate excluded tests. + details['object'] = excluded_tests + for excluded_test_expansion in excluded_tests: + assert_contains_only_fields(excluded_test_expansion, + valid_test_expansion_fields) + details['object'] = excluded_test_expansion + for artifact in test_expansion_schema: + details['test_expansion_field'] = artifact + assert_atom_or_list_items_from( + excluded_test_expansion, + artifact, + ['*'] + test_expansion_schema[artifact]) + del details['test_expansion_field'] + + # Validate subresource paths. + details['object'] = subresource_path + assert_contains_only_fields(subresource_path, + test_expansion_schema['subresource']); + + for subresource in subresource_path: + local_rel_path = "." + subresource_path[subresource] + full_path = os.path.join(test_root_directory, local_rel_path) + assert os.path.isfile(full_path), "%s is not an existing file" % path + + del details['object'] + + +def assert_valid_spec_json(spec_json): + error_details = {} + try: + validate(spec_json, error_details) + except AssertionError, err: + print 'ERROR:', err.message + print json.dumps(error_details, indent=4) + sys.exit(1) + + +def main(): + spec_json = load_spec_json(); + assert_valid_spec_json(spec_json) + print "Spec JSON is valid." + + +if __name__ == '__main__': + main() diff --git a/testing/web-platform/tests/referrer-policy/generic/unsupported-csp-referrer-directive.html b/testing/web-platform/tests/referrer-policy/generic/unsupported-csp-referrer-directive.html new file mode 100644 index 000000000..a40dded44 --- /dev/null +++ b/testing/web-platform/tests/referrer-policy/generic/unsupported-csp-referrer-directive.html @@ -0,0 +1,30 @@ +<!DOCTYPE html> +<html> + <head> + <title>Referrer Policy: CSP 'referrer' directive should not be supported</title> + <meta http-equiv="Content-Security-Policy" content="referrer no-referrer"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <!-- Common global functions for referrer-policy tests. --> + <script src="/referrer-policy/generic/common.js"></script> + </head> + <body> + <h1>Referrer Policy: CSP 'referrer' directive should not be supported</h1> + <p>CSP used to have a 'referrer' directive to set a Referrer Policy. This directive has been removed and should not be supported.</p> + + <pre id="received_message">Running...</pre> + + <script> + var test = async_test("Image has a referrer despite CSP 'referrer' directive"); + var urlPath = '/referrer-policy/generic/subresource/image.py'; + var url = location.protocol + "//www1." + location.hostname + ":" + location.port + + urlPath; + queryImage(url, test.step_func(function(message) { + assert_equals(message.referrer, document.location.href); + test.done(); + })); + </script> + + <div id="log"></div> + </body> +</html> |