summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/mixed-content/generic/common.js
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/mixed-content/generic/common.js')
-rw-r--r--testing/web-platform/tests/mixed-content/generic/common.js398
1 files changed, 398 insertions, 0 deletions
diff --git a/testing/web-platform/tests/mixed-content/generic/common.js b/testing/web-platform/tests/mixed-content/generic/common.js
new file mode 100644
index 000000000..36427a466
--- /dev/null
+++ b/testing/web-platform/tests/mixed-content/generic/common.js
@@ -0,0 +1,398 @@
+/**
+ * @fileoverview Utilities for mixed-content in Web Platform Tests.
+ * @author burnik@google.com (Kristijan Burnik)
+ * Disclaimer: Some methods of other authors are annotated in the corresponding
+ * method's JSDoc.
+ */
+
+/**
+ * Normalizes the target port for use in a URL. For default ports, this is the
+ * empty string (omitted port), otherwise it's a colon followed by the port
+ * number. Ports 80, 443 and an empty string are regarded as default ports.
+ * @param {number} targetPort The port to use
+ * @return {string} The port portion for using as part of a URL.
+ */
+function getNormalizedPort(targetPort) {
+ return ([80, 443, ""].indexOf(targetPort) >= 0) ? "" : ":" + targetPort;
+}
+
+/**
+ * Creates a GUID.
+ * See: https://en.wikipedia.org/wiki/Globally_unique_identifier
+ * Original author: broofa (http://www.broofa.com/)
+ * Sourced from: http://stackoverflow.com/a/2117523/4949715
+ * @return {string} A pseudo-random GUID.
+ */
+function guid() {
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
+ var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
+ return v.toString(16);
+ });
+}
+
+/**
+ * Initiates a new XHR via GET.
+ * @param {string} url The endpoint URL for the XHR.
+ * @param {string} responseType Optional - how should the response be parsed.
+ * Default is "json".
+ * See: https://xhr.spec.whatwg.org/#dom-xmlhttprequest-responsetype
+ * @return {Promise} A promise wrapping the success and error events.
+ */
+function xhrRequest(url, responseType) {
+ return new Promise(function(resolve, reject) {
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', url, true);
+ xhr.responseType = responseType || "json";
+
+ xhr.addEventListener("error", function() {
+ reject(Error("Network Error"));
+ });
+
+ xhr.addEventListener("load", function() {
+ if (xhr.status != 200)
+ return reject(Error(xhr.statusText));
+
+ resolve(xhr.response);
+ });
+
+ xhr.send();
+ });
+}
+
+/**
+ * Sets attributes on a given DOM element.
+ * @param {DOMElement} element The element on which to set the attributes.
+ * @param {object} An object with keys (serving as attribute names) and values.
+ */
+function setAttributes(el, attrs) {
+ attrs = attrs || {}
+ for (var attr in attrs)
+ el.setAttribute(attr, attrs[attr]);
+}
+
+
+/**
+ * Binds to success and error events of an object wrapping them into a promise
+ * available through {@code element.eventPromise}. The success event
+ * resolves and error event rejects.
+ * @param {object} element An object supporting events on which to bind the
+ * promise.
+ * @param {string} resolveEventName [="load"] The event name to bind resolve to.
+ * @param {string} rejectEventName [="error"] The event name to bind reject to.
+ */
+function bindEvents(element, resolveEventName, rejectEventName) {
+ element.eventPromise = new Promise(function(resolve, reject) {
+ element.addEventListener(resolveEventName || "load", resolve);
+ element.addEventListener(rejectEventName || "error",
+ function(e) { e.preventDefault(); reject(); } );
+ });
+}
+
+/**
+ * Creates a new DOM element.
+ * @param {string} tagName The type of the DOM element.
+ * @param {object} attrs A JSON with attributes to apply to the element.
+ * @param {DOMElement} parent Optional - an existing DOM element to append to
+ * If not provided, the returned element will remain orphaned.
+ * @param {boolean} doBindEvents Optional - Whether to bind to load and error
+ * events and provide the promise wrapping the events via the element's
+ * {@code eventPromise} property. Default value evaluates to false.
+ * @return {DOMElement} The newly created DOM element.
+ */
+function createElement(tagName, attrs, parent, doBindEvents) {
+ var element = document.createElement(tagName);
+
+ if (doBindEvents)
+ bindEvents(element);
+
+ // We set the attributes after binding to events to catch any
+ // event-triggering attribute changes. E.g. form submission.
+ //
+ // But be careful with images: unlike other elements they will start the load
+ // as soon as the attr is set, even if not in the document yet, and sometimes
+ // complete it synchronously, so the append doesn't have the effect we want.
+ // So for images, we want to set the attrs after appending, whereas for other
+ // elements we want to do it before appending.
+ var isImg = (tagName == "img");
+ if (!isImg)
+ setAttributes(element, attrs);
+
+ if (parent)
+ parent.appendChild(element);
+
+ if (isImg)
+ setAttributes(element, attrs);
+
+ return element;
+}
+
+function createRequestViaElement(tagName, attrs, parent) {
+ return createElement(tagName, attrs, parent, true).eventPromise;
+}
+
+/**
+ * Creates a new empty iframe and appends it to {@code document.body} .
+ * @param {string} name The name and ID of the new iframe.
+ * @param {boolean} doBindEvents Whether to bind load and error events.
+ * @return {DOMElement} The newly created iframe.
+ */
+function createHelperIframe(name, doBindEvents) {
+ return createElement("iframe",
+ {"name": name, "id": name},
+ document.body,
+ doBindEvents);
+}
+
+/**
+ * Creates a new iframe, binds load and error events, sets the src attribute and
+ * appends it to {@code document.body} .
+ * @param {string} url The src for the iframe.
+ * @return {Promise} The promise for success/error events.
+ */
+function requestViaIframe(url) {
+ return createRequestViaElement("iframe", {"src": url}, document.body);
+}
+
+/**
+ * Creates a new image, binds load and error events, sets the src attribute and
+ * appends it to {@code document.body} .
+ * @param {string} url The src for the image.
+ * @return {Promise} The promise for success/error events.
+ */
+function requestViaImage(url) {
+ return createRequestViaElement("img", {"src": url}, document.body);
+}
+
+/**
+ * Initiates a new XHR GET request to provided URL.
+ * @param {string} url The endpoint URL for the XHR.
+ * @return {Promise} The promise for success/error events.
+ */
+function requestViaXhr(url) {
+ return xhrRequest(url);
+}
+
+/**
+ * Initiates a new GET request to provided URL via the Fetch API.
+ * @param {string} url The endpoint URL for the Fetch.
+ * @return {Promise} The promise for success/error events.
+ */
+function requestViaFetch(url) {
+ return fetch(url);
+}
+
+/**
+ * Creates a new Worker, binds message and error events wrapping them into.
+ * {@code worker.eventPromise} and posts an empty string message to start
+ * the worker.
+ * @param {string} url The endpoint URL for the worker script.
+ * @return {Promise} The promise for success/error events.
+ */
+function requestViaWorker(url) {
+ var worker = new Worker(url);
+ bindEvents(worker, "message", "error");
+ worker.postMessage('');
+
+ return worker.eventPromise;
+}
+
+/**
+ * Sets the href attribute on a navigable DOM element and performs a navigation
+ * by clicking it. To avoid navigating away from the current execution
+ * context, a target attribute is set to point to a new helper iframe.
+ * @param {DOMElement} navigableElement The navigable DOMElement
+ * @param {string} url The href for the navigable element.
+ * @return {Promise} The promise for success/error events.
+ */
+function requestViaNavigable(navigableElement, url) {
+ var iframe = createHelperIframe(guid(), true);
+ setAttributes(navigableElement,
+ {"href": url,
+ "target": iframe.name});
+ navigableElement.click();
+
+ return iframe.eventPromise;
+}
+
+/**
+ * Creates a new anchor element, appends it to {@code document.body} and
+ * performs the navigation.
+ * @param {string} url The URL to navigate to.
+ * @return {Promise} The promise for success/error events.
+ */
+function requestViaAnchor(url) {
+ var a = createElement("a", {"innerHTML": "Link to resource"}, document.body);
+
+ return requestViaNavigable(a, url);
+}
+
+/**
+ * Creates a new area element, appends it to {@code document.body} and performs
+ * the navigation.
+ * @param {string} url The URL to navigate to.
+ * @return {Promise} The promise for success/error events.
+ */
+function requestViaArea(url) {
+ var area = createElement("area", {}, document.body);
+
+ return requestViaNavigable(area, url);
+}
+
+/**
+ * Creates a new script element, sets the src to url, and appends it to
+ * {@code document.body}.
+ * @param {string} url The src URL.
+ * @return {Promise} The promise for success/error events.
+ */
+function requestViaScript(url) {
+ return createRequestViaElement("script", {"src": url}, document.body);
+}
+
+/**
+ * Creates a new form element, sets attributes, appends it to
+ * {@code document.body} and submits the form.
+ * @param {string} url The URL to submit to.
+ * @return {Promise} The promise for success/error events.
+ */
+function requestViaForm(url) {
+ var iframe = createHelperIframe(guid());
+ var form = createElement("form",
+ {"action": url,
+ "method": "POST",
+ "target": iframe.name},
+ document.body);
+ bindEvents(iframe);
+ form.submit();
+
+ return iframe.eventPromise;
+}
+
+/**
+ * Creates a new link element for a stylesheet, binds load and error events,
+ * sets the href to url and appends it to {@code document.head}.
+ * @param {string} url The URL for a stylesheet.
+ * @return {Promise} The promise for success/error events.
+ */
+function requestViaLinkStylesheet(url) {
+ return createRequestViaElement("link",
+ {"rel": "stylesheet", "href": url},
+ document.head);
+}
+
+/**
+ * Creates a new link element for a prefetch, binds load and error events, sets
+ * the href to url and appends it to {@code document.head}.
+ * @param {string} url The URL of a resource to prefetch.
+ * @return {Promise} The promise for success/error events.
+ */
+function requestViaLinkPrefetch(url) {
+ // TODO(kristijanburnik): Check if prefetch should support load and error
+ // events. For now we assume it's not specified.
+ // https://developer.mozilla.org/en-US/docs/Web/HTTP/Link_prefetching_FAQ
+ return createRequestViaElement("link",
+ {"rel": "prefetch", "href": url},
+ document.head);
+}
+
+/**
+ * Creates a new media element with a child source element, binds loadeddata and
+ * error events, sets attributes and appends to document.body.
+ * @param {string} type The type of the media element (audio/video/picture).
+ * @param {object} media_attrs The attributes for the media element.
+ * @param {object} source_attrs The attributes for the child source element.
+ * @return {DOMElement} The newly created media element.
+ */
+function createMediaElement(type, media_attrs, source_attrs) {
+ var mediaElement = createElement(type, {});
+ var sourceElement = createElement("source", {}, mediaElement);
+
+ mediaElement.eventPromise = new Promise(function(resolve, reject) {
+ mediaElement.addEventListener("loadeddata", resolve);
+ // Notice that the source element will raise the error.
+ sourceElement.addEventListener("error", reject);
+ });
+
+ setAttributes(mediaElement, media_attrs);
+ setAttributes(sourceElement, source_attrs);
+ document.body.appendChild(mediaElement);
+
+ return mediaElement;
+}
+
+/**
+ * Creates a new video element, binds loadeddata and error events, sets
+ * attributes and source URL and appends to {@code document.body}.
+ * @param {string} url The URL of the video.
+ * @return {Promise} The promise for success/error events.
+ */
+function requestViaVideo(url) {
+ return createMediaElement("video",
+ {},
+ {type: "video/mp4", src: url}).eventPromise;
+}
+
+/**
+ * Creates a new audio element, binds loadeddata and error events, sets
+ * attributes and source URL and appends to {@code document.body}.
+ * @param {string} url The URL of the audio.
+ * @return {Promise} The promise for success/error events.
+ */
+function requestViaAudio(url) {
+ return createMediaElement("audio",
+ {},
+ {type: "audio/mpeg", src: url}).eventPromise;
+}
+
+/**
+ * Creates a new picture element, binds loadeddata and error events, sets
+ * attributes and source URL and appends to {@code document.body}. Also
+ * creates new image element appending it to the picture
+ * @param {string} url The URL of the image for the source and image elements.
+ * @return {Promise} The promise for success/error events.
+ */
+function requestViaPicture(url) {
+ var picture = createMediaElement("picture", {}, {"srcset": url,
+ "type": "image/png"});
+ return createRequestViaElement("img", {"src": url}, picture);
+}
+
+/**
+ * Creates a new object element, binds load and error events, sets the data to
+ * url, and appends it to {@code document.body}.
+ * @param {string} url The data URL.
+ * @return {Promise} The promise for success/error events.
+ */
+function requestViaObject(url) {
+ return createRequestViaElement("object", {"data": url}, document.body);
+}
+
+/**
+ * Creates a new WebSocket pointing to {@code url} and sends a message string
+ * "echo". The {@code message} and {@code error} events are triggering the
+ * returned promise resolve/reject events.
+ * @param {string} url The URL for WebSocket to connect to.
+ * @return {Promise} The promise for success/error events.
+ */
+function requestViaWebSocket(url) {
+ return new Promise(function(resolve, reject) {
+ var websocket = new WebSocket(url);
+
+ websocket.addEventListener("message", function(e) {
+ resolve(JSON.parse(e.data));
+ });
+
+ websocket.addEventListener("open", function(e) {
+ websocket.send("echo");
+ });
+
+ websocket.addEventListener("error", function(e) {
+ reject(e)
+ });
+ });
+}
+
+// SanityChecker does nothing in release mode. See sanity-checker.js for debug
+// mode.
+function SanityChecker() {}
+SanityChecker.prototype.checkScenario = function() {};
+SanityChecker.prototype.setFailTimeout = function(test, timeout) {};