mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-18 05:07:31 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
16
browser/components/originattributes/moz.build
Normal file
16
browser/components/originattributes/moz.build
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += [
|
||||
'test/browser/browser.ini',
|
||||
]
|
||||
|
||||
MOCHITEST_MANIFESTS += [
|
||||
'test/mochitest/mochitest.ini'
|
||||
]
|
||||
|
||||
with Files('**'):
|
||||
BUG_COMPONENT = ('Firefox', 'OriginAttributes')
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"../../../../../testing/mochitest/browser.eslintrc.js"
|
||||
]
|
||||
};
|
||||
64
browser/components/originattributes/test/browser/browser.ini
Normal file
64
browser/components/originattributes/test/browser/browser.ini
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
[DEFAULT]
|
||||
tags = usercontextid firstpartyisolation originattributes
|
||||
support-files =
|
||||
dummy.html
|
||||
file_broadcastChannel.html
|
||||
file_broadcastChanneliFrame.html
|
||||
file_cache.html
|
||||
file_favicon.html
|
||||
file_favicon.png
|
||||
file_favicon.png^headers^
|
||||
file_favicon_cache.html
|
||||
file_favicon_cache.png
|
||||
file_favicon_thirdParty.html
|
||||
file_firstPartyBasic.html
|
||||
file_sharedworker.html
|
||||
file_sharedworker.js
|
||||
file_thirdPartyChild.audio.ogg
|
||||
file_thirdPartyChild.embed.png
|
||||
file_thirdPartyChild.fetch.html
|
||||
file_thirdPartyChild.iframe.html
|
||||
file_thirdPartyChild.img.png
|
||||
file_thirdPartyChild.import.js
|
||||
file_thirdPartyChild.link.css
|
||||
file_thirdPartyChild.object.png
|
||||
file_thirdPartyChild.request.html
|
||||
file_thirdPartyChild.script.js
|
||||
file_thirdPartyChild.sharedworker.js
|
||||
file_thirdPartyChild.track.vtt
|
||||
file_thirdPartyChild.video.ogv
|
||||
file_thirdPartyChild.worker.fetch.html
|
||||
file_thirdPartyChild.worker.js
|
||||
file_thirdPartyChild.worker.request.html
|
||||
file_thirdPartyChild.worker.xhr.html
|
||||
file_thirdPartyChild.xhr.html
|
||||
head.js
|
||||
test.js
|
||||
test.js^headers^
|
||||
test.html
|
||||
test2.html
|
||||
test2.js
|
||||
test2.js^headers^
|
||||
test_firstParty.html
|
||||
test_firstParty_cookie.html
|
||||
test_firstParty_html_redirect.html
|
||||
test_firstParty_http_redirect.html
|
||||
test_firstParty_http_redirect.html^headers^
|
||||
test_firstParty_iframe_http_redirect.html
|
||||
test_firstParty_postMessage.html
|
||||
window.html
|
||||
worker_blobify.js
|
||||
worker_deblobify.js
|
||||
|
||||
[browser_broadcastChannel.js]
|
||||
[browser_cache.js]
|
||||
[browser_cookieIsolation.js]
|
||||
[browser_favicon_firstParty.js]
|
||||
[browser_favicon_userContextId.js]
|
||||
[browser_firstPartyIsolation.js]
|
||||
[browser_localStorageIsolation.js]
|
||||
[browser_blobURLIsolation.js]
|
||||
[browser_imageCacheIsolation.js]
|
||||
[browser_sharedworker.js]
|
||||
[browser_httpauth.js]
|
||||
[browser_clientAuth.js]
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
/**
|
||||
* Bug 1264573 - A test case for blob url isolation.
|
||||
*/
|
||||
|
||||
const TEST_PAGE = "http://mochi.test:8888/browser/browser/components/" +
|
||||
"originattributes/test/browser/file_firstPartyBasic.html";
|
||||
const SCRIPT_WORKER_BLOBIFY = "worker_blobify.js";
|
||||
const SCRIPT_WORKER_DEBLOBIFY = "worker_deblobify.js";
|
||||
|
||||
function page_blobify(browser, input) {
|
||||
return ContentTask.spawn(browser, input, function(input) {
|
||||
return { blobURL: content.URL.createObjectURL(new content.Blob([input])) };
|
||||
});
|
||||
}
|
||||
|
||||
function page_deblobify(browser, blobURL) {
|
||||
return ContentTask.spawn(browser, blobURL, function* (blobURL) {
|
||||
if ("error" in blobURL) {
|
||||
return blobURL;
|
||||
}
|
||||
blobURL = blobURL.blobURL;
|
||||
|
||||
function blobURLtoBlob(blobURL) {
|
||||
return new content.Promise(function (resolve) {
|
||||
let xhr = new content.XMLHttpRequest();
|
||||
xhr.open("GET", blobURL, true);
|
||||
xhr.onload = function () {
|
||||
resolve(xhr.response);
|
||||
};
|
||||
xhr.onerror = function () {
|
||||
resolve("xhr error");
|
||||
};
|
||||
xhr.responseType = "blob";
|
||||
xhr.send();
|
||||
});
|
||||
}
|
||||
|
||||
function blobToString(blob) {
|
||||
return new content.Promise(function (resolve) {
|
||||
let fileReader = new content.FileReader();
|
||||
fileReader.onload = function () {
|
||||
resolve(fileReader.result);
|
||||
};
|
||||
fileReader.readAsText(blob);
|
||||
});
|
||||
}
|
||||
|
||||
let blob = yield blobURLtoBlob(blobURL);
|
||||
if (blob == "xhr error") {
|
||||
return "xhr error";
|
||||
}
|
||||
|
||||
return yield blobToString(blob);
|
||||
});
|
||||
}
|
||||
|
||||
function workerIO(browser, scriptFile, message) {
|
||||
return ContentTask.spawn(browser, {scriptFile, message}, function* (args) {
|
||||
let worker = new content.Worker(args.scriptFile);
|
||||
let promise = new content.Promise(function(resolve) {
|
||||
let listenFunction = function(event) {
|
||||
worker.removeEventListener("message", listenFunction, false);
|
||||
worker.terminate();
|
||||
resolve(event.data);
|
||||
};
|
||||
worker.addEventListener("message", listenFunction, false);
|
||||
});
|
||||
worker.postMessage(args.message);
|
||||
return yield promise;
|
||||
});
|
||||
}
|
||||
|
||||
let worker_blobify = (browser, input) => workerIO(browser, SCRIPT_WORKER_BLOBIFY, input);
|
||||
let worker_deblobify = (browser, blobURL) => workerIO(browser, SCRIPT_WORKER_DEBLOBIFY, blobURL);
|
||||
|
||||
function doTest(blobify, deblobify) {
|
||||
let blobURL = null;
|
||||
return function* (browser) {
|
||||
if (blobURL === null) {
|
||||
let input = Math.random().toString();
|
||||
blobURL = yield blobify(browser, input);
|
||||
return input;
|
||||
}
|
||||
let result = yield deblobify(browser, blobURL);
|
||||
blobURL = null;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
let tests = [];
|
||||
for (let blobify of [page_blobify, worker_blobify]) {
|
||||
for (let deblobify of [page_deblobify, worker_deblobify]) {
|
||||
tests.push(doTest(blobify, deblobify));
|
||||
}
|
||||
}
|
||||
|
||||
IsolationTestTools.runTests(TEST_PAGE, tests);
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Bug 1264571 - A test case of broadcast channels for first party isolation.
|
||||
*/
|
||||
|
||||
const TEST_DOMAIN = "http://example.net/";
|
||||
const TEST_PATH = TEST_DOMAIN + "browser/browser/components/originattributes/test/browser/";
|
||||
const TEST_PAGE = TEST_PATH + "file_broadcastChannel.html";
|
||||
|
||||
function* doTest(aBrowser) {
|
||||
let response = yield ContentTask.spawn(aBrowser, null, function* () {
|
||||
|
||||
let displayItem = content.document.getElementById("display");
|
||||
|
||||
// If there is nothing in the 'display', we will try to send a message to
|
||||
// the broadcast channel and wait until this message has been delivered.
|
||||
// The way that how we make sure the message is delivered is based on an
|
||||
// iframe which will reply everything it receives from the broadcast channel
|
||||
// to the current window through the postMessage. So, we can know that the
|
||||
// boradcast message is sent successfully when the window receives a message
|
||||
// from the iframe.
|
||||
if (displayItem.innerHTML === "") {
|
||||
let data = Math.random().toString();
|
||||
|
||||
let receivedData = yield new Promise(resolve => {
|
||||
let listenFunc = event => {
|
||||
content.removeEventListener("message", listenFunc);
|
||||
resolve(event.data);
|
||||
};
|
||||
|
||||
let bc = new content.BroadcastChannel("testBroadcastChannel");
|
||||
|
||||
content.addEventListener("message", listenFunc, false);
|
||||
bc.postMessage(data);
|
||||
});
|
||||
|
||||
is(receivedData, data, "The value should be the same.");
|
||||
|
||||
return receivedData;
|
||||
}
|
||||
|
||||
return displayItem.innerHTML;
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
IsolationTestTools.runTests(TEST_PAGE, doTest);
|
||||
|
|
@ -0,0 +1,259 @@
|
|||
/*
|
||||
* Bug 1264577 - A test case for testing caches of various submodules.
|
||||
* This test case will load two pages that each page loads various resources
|
||||
* within the same third party domain for the same originAttributes or different
|
||||
* originAttributes. And then, it verifies the number of cache entries and
|
||||
* the originAttributes of loading channels. If these two pages belong to
|
||||
* the same originAttributes, the number of cache entries for a certain
|
||||
* resource would be one. Otherwise, it would be two.
|
||||
*/
|
||||
|
||||
const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
let {LoadContextInfo} = Cu.import("resource://gre/modules/LoadContextInfo.jsm", {});
|
||||
let protocolProxyService = Cc["@mozilla.org/network/protocol-proxy-service;1"]
|
||||
.getService(Ci.nsIProtocolProxyService);
|
||||
|
||||
const TEST_DOMAIN = "http://example.net";
|
||||
const TEST_PATH = "/browser/browser/components/originattributes/test/browser/";
|
||||
const TEST_PAGE = TEST_DOMAIN + TEST_PATH + "file_cache.html";
|
||||
|
||||
let suffixes = ["iframe.html", "link.css", "script.js", "img.png", "object.png",
|
||||
"embed.png", "xhr.html", "worker.xhr.html", "audio.ogg",
|
||||
"video.ogv", "track.vtt",
|
||||
"fetch.html", "worker.fetch.html",
|
||||
"request.html", "worker.request.html",
|
||||
"import.js", "worker.js", "sharedworker.js"];
|
||||
|
||||
// A random value for isolating video/audio elements across different tests.
|
||||
let randomSuffix;
|
||||
|
||||
function clearAllImageCaches() {
|
||||
let tools = SpecialPowers.Cc["@mozilla.org/image/tools;1"]
|
||||
.getService(SpecialPowers.Ci.imgITools);
|
||||
let imageCache = tools.getImgCacheForDocument(window.document);
|
||||
imageCache.clearCache(true); // true=chrome
|
||||
imageCache.clearCache(false); // false=content
|
||||
}
|
||||
|
||||
function cacheDataForContext(loadContextInfo) {
|
||||
return new Promise(resolve => {
|
||||
let cacheEntries = [];
|
||||
let cacheVisitor = {
|
||||
onCacheStorageInfo(num, consumption) {},
|
||||
onCacheEntryInfo(uri, idEnhance) {
|
||||
cacheEntries.push({ uri: uri,
|
||||
idEnhance: idEnhance });
|
||||
},
|
||||
onCacheEntryVisitCompleted() {
|
||||
resolve(cacheEntries);
|
||||
},
|
||||
QueryInterface(iid) {
|
||||
if (iid.equals(Ci.nsICacheStorageVisitor))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
};
|
||||
// Visiting the disk cache also visits memory storage so we do not
|
||||
// need to use Services.cache2.memoryCacheStorage() here.
|
||||
let storage = Services.cache2.diskCacheStorage(loadContextInfo, false);
|
||||
storage.asyncVisitStorage(cacheVisitor, true);
|
||||
});
|
||||
}
|
||||
|
||||
let countMatchingCacheEntries = function (cacheEntries, domain, fileSuffix) {
|
||||
return cacheEntries.map(entry => entry.uri.asciiSpec)
|
||||
.filter(spec => spec.includes(domain))
|
||||
.filter(spec => spec.includes("file_thirdPartyChild." + fileSuffix))
|
||||
.length;
|
||||
};
|
||||
|
||||
function observeChannels(onChannel) {
|
||||
// We use a dummy proxy filter to catch all channels, even those that do not
|
||||
// generate an "http-on-modify-request" notification, such as link preconnects.
|
||||
let proxyFilter = {
|
||||
applyFilter : function (aProxyService, aChannel, aProxy) {
|
||||
// We have the channel; provide it to the callback.
|
||||
onChannel(aChannel);
|
||||
// Pass on aProxy unmodified.
|
||||
return aProxy;
|
||||
}
|
||||
};
|
||||
protocolProxyService.registerChannelFilter(proxyFilter, 0);
|
||||
// Return the stop() function:
|
||||
return () => protocolProxyService.unregisterChannelFilter(proxyFilter);
|
||||
}
|
||||
|
||||
function startObservingChannels(aMode) {
|
||||
let stopObservingChannels = observeChannels(function (channel) {
|
||||
let originalURISpec = channel.originalURI.spec;
|
||||
if (originalURISpec.includes("example.net")) {
|
||||
let loadInfo = channel.loadInfo;
|
||||
|
||||
switch (aMode) {
|
||||
case TEST_MODE_FIRSTPARTY:
|
||||
ok(loadInfo.originAttributes.firstPartyDomain === "example.com" ||
|
||||
loadInfo.originAttributes.firstPartyDomain === "example.org",
|
||||
"first party for " + originalURISpec + " is " + loadInfo.originAttributes.firstPartyDomain);
|
||||
break;
|
||||
|
||||
case TEST_MODE_NO_ISOLATION:
|
||||
ok(ChromeUtils.isOriginAttributesEqual(loadInfo.originAttributes, ChromeUtils.fillNonDefaultOriginAttributes()),
|
||||
"OriginAttributes for " + originalURISpec + " is default.");
|
||||
break;
|
||||
|
||||
case TEST_MODE_CONTAINERS:
|
||||
ok(loadInfo.originAttributes.userContextId === 1 ||
|
||||
loadInfo.originAttributes.userContextId === 2,
|
||||
"userContextId for " + originalURISpec + " is " + loadInfo.originAttributes.userContextId);
|
||||
break;
|
||||
|
||||
default:
|
||||
ok(false, "Unknown test mode.");
|
||||
}
|
||||
}
|
||||
});
|
||||
return stopObservingChannels;
|
||||
}
|
||||
|
||||
let stopObservingChannels;
|
||||
|
||||
// The init function, which clears image and network caches, and generates
|
||||
// the random value for isolating video and audio elements across different
|
||||
// test runs.
|
||||
function* doInit(aMode) {
|
||||
yield SpecialPowers.pushPrefEnv({"set": [["network.predictor.enabled", false],
|
||||
["network.predictor.enable-prefetch", false]]});
|
||||
clearAllImageCaches();
|
||||
|
||||
let networkCache = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
|
||||
.getService(Ci.nsICacheStorageService);
|
||||
networkCache.clear();
|
||||
|
||||
randomSuffix = Math.random();
|
||||
stopObservingChannels = startObservingChannels(aMode);
|
||||
}
|
||||
|
||||
// In the test function, we dynamically generate the video and audio element,
|
||||
// and assign a random suffix to their URL to isolate them across different
|
||||
// test runs.
|
||||
function* doTest(aBrowser) {
|
||||
|
||||
let argObj = {
|
||||
randomSuffix: randomSuffix,
|
||||
urlPrefix: TEST_DOMAIN + TEST_PATH,
|
||||
};
|
||||
|
||||
yield ContentTask.spawn(aBrowser, argObj, function* (arg) {
|
||||
let videoURL = arg.urlPrefix + "file_thirdPartyChild.video.ogv";
|
||||
let audioURL = arg.urlPrefix + "file_thirdPartyChild.audio.ogg";
|
||||
let trackURL = arg.urlPrefix + "file_thirdPartyChild.track.vtt";
|
||||
let URLSuffix = "?r=" + arg.randomSuffix;
|
||||
|
||||
// Create the audio and video elements.
|
||||
let audio = content.document.createElement('audio');
|
||||
let video = content.document.createElement('video');
|
||||
let audioSource = content.document.createElement('source');
|
||||
let audioTrack = content.document.createElement('track');
|
||||
|
||||
// Append the audio and track element into the body, and wait until they're finished.
|
||||
yield new Promise(resolve => {
|
||||
let audioLoaded = false;
|
||||
let trackLoaded = false;
|
||||
|
||||
let audioListener = () => {
|
||||
audio.removeEventListener("canplaythrough", audioListener);
|
||||
|
||||
audioLoaded = true;
|
||||
if (audioLoaded && trackLoaded) {
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
|
||||
let trackListener = () => {
|
||||
audioTrack.removeEventListener("load", trackListener);
|
||||
|
||||
trackLoaded = true;
|
||||
if (audioLoaded && trackLoaded) {
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
|
||||
// Add the event listeners before everything in case we lose events.
|
||||
audioTrack.addEventListener("load", trackListener, false);
|
||||
audio.addEventListener("canplaythrough", audioListener, false);
|
||||
|
||||
// Assign attributes for the audio element.
|
||||
audioSource.setAttribute("src", audioURL + URLSuffix);
|
||||
audioSource.setAttribute("type", "audio/ogg");
|
||||
audioTrack.setAttribute("src", trackURL);
|
||||
audioTrack.setAttribute("kind", "subtitles");
|
||||
|
||||
audio.appendChild(audioSource);
|
||||
audio.appendChild(audioTrack);
|
||||
audio.autoplay = true;
|
||||
|
||||
content.document.body.appendChild(audio);
|
||||
});
|
||||
|
||||
// Append the video element into the body, and wait until it's finished.
|
||||
yield new Promise(resolve => {
|
||||
let listener = () => {
|
||||
video.removeEventListener("canplaythrough", listener);
|
||||
resolve();
|
||||
};
|
||||
|
||||
// Add the event listener before everything in case we lose the event.
|
||||
video.addEventListener("canplaythrough", listener, false);
|
||||
|
||||
// Assign attributes for the video element.
|
||||
video.setAttribute("src", videoURL + URLSuffix);
|
||||
video.setAttribute("type", "video/ogg");
|
||||
|
||||
content.document.body.appendChild(video);
|
||||
});
|
||||
});
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The check function, which checks the number of cache entries.
|
||||
function* doCheck(aShouldIsolate, aInputA, aInputB) {
|
||||
let expectedEntryCount = 1;
|
||||
let data = [];
|
||||
data = data.concat(yield cacheDataForContext(LoadContextInfo.default));
|
||||
data = data.concat(yield cacheDataForContext(LoadContextInfo.private));
|
||||
data = data.concat(yield cacheDataForContext(LoadContextInfo.custom(true, {})));
|
||||
data = data.concat(yield cacheDataForContext(LoadContextInfo.custom(false, { userContextId: 1 })));
|
||||
data = data.concat(yield cacheDataForContext(LoadContextInfo.custom(true, { userContextId: 1 })));
|
||||
data = data.concat(yield cacheDataForContext(LoadContextInfo.custom(false, { userContextId: 2 })));
|
||||
data = data.concat(yield cacheDataForContext(LoadContextInfo.custom(true, { userContextId: 2 })));
|
||||
data = data.concat(yield cacheDataForContext(LoadContextInfo.custom(false, { firstPartyDomain: "example.com" })));
|
||||
data = data.concat(yield cacheDataForContext(LoadContextInfo.custom(true, { firstPartyDomain: "example.com" })));
|
||||
data = data.concat(yield cacheDataForContext(LoadContextInfo.custom(false, { firstPartyDomain: "example.org" })));
|
||||
data = data.concat(yield cacheDataForContext(LoadContextInfo.custom(true, { firstPartyDomain: "example.org" })));
|
||||
|
||||
if (aShouldIsolate) {
|
||||
expectedEntryCount = 2;
|
||||
}
|
||||
|
||||
for (let suffix of suffixes) {
|
||||
let foundEntryCount = countMatchingCacheEntries(data, "example.net", suffix);
|
||||
let result = (expectedEntryCount === foundEntryCount);
|
||||
ok(result, "Cache entries expected for " + suffix + ": " + expectedEntryCount +
|
||||
", and found " + foundEntryCount);
|
||||
}
|
||||
|
||||
stopObservingChannels();
|
||||
stopObservingChannels = undefined;
|
||||
return true;
|
||||
}
|
||||
|
||||
let testArgs = {
|
||||
url: TEST_PAGE,
|
||||
firstFrameSetting: DEFAULT_FRAME_SETTING,
|
||||
secondFrameSetting: [TEST_TYPE_FRAME],
|
||||
};
|
||||
|
||||
IsolationTestTools.runTests(testArgs, doTest, doCheck, doInit);
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
let certCached = true;
|
||||
let secondTabStarted = false;
|
||||
|
||||
function onCertDialogLoaded(subject) {
|
||||
certCached = false;
|
||||
// Click OK.
|
||||
subject.acceptDialog();
|
||||
}
|
||||
|
||||
Services.obs.addObserver(onCertDialogLoaded, "cert-dialog-loaded", false);
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
Services.obs.removeObserver(onCertDialogLoaded, "cert-dialog-loaded");
|
||||
});
|
||||
|
||||
function* setup() {
|
||||
yield SpecialPowers.pushPrefEnv({
|
||||
set: [["security.default_personal_cert", "Ask Every Time"]]
|
||||
});
|
||||
}
|
||||
|
||||
function getResult() {
|
||||
// The first tab always returns true.
|
||||
if (!secondTabStarted) {
|
||||
certCached = true;
|
||||
secondTabStarted = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// The second tab returns true if the cert is cached, so it will be different
|
||||
// from the result of the first tab, and considered isolated.
|
||||
let ret = certCached;
|
||||
certCached = true;
|
||||
secondTabStarted = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// aGetResultImmediately must be true because we need to get the result before
|
||||
// the next tab is opened.
|
||||
IsolationTestTools.runTests("https://requireclientcert.example.com",
|
||||
getResult,
|
||||
null, // aCompareResultFunc
|
||||
setup, // aBeginFunc
|
||||
true); // aGetResultImmediately
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
* Bug 1312541 - A test case for document.cookie isolation.
|
||||
*/
|
||||
|
||||
const TEST_PAGE = "http://mochi.test:8888/browser/browser/components/" +
|
||||
"originattributes/test/browser/file_firstPartyBasic.html";
|
||||
|
||||
// Use a random key so we don't access it in later tests.
|
||||
const key = "key" + Math.random().toString();
|
||||
const re = new RegExp(key + "=([0-9\.]+)");
|
||||
|
||||
// Define the testing function
|
||||
function* doTest(aBrowser) {
|
||||
return yield ContentTask.spawn(aBrowser, {key, re},
|
||||
function ({key, re}) {
|
||||
let result = re.exec(content.document.cookie);
|
||||
if (result) {
|
||||
return result[1];
|
||||
}
|
||||
// No value is found, so we create one.
|
||||
let value = Math.random().toString();
|
||||
content.document.cookie = key + "=" + value;
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
Services.cookies.removeAll();
|
||||
});
|
||||
|
||||
IsolationTestTools.runTests(TEST_PAGE, doTest);
|
||||
|
|
@ -0,0 +1,343 @@
|
|||
/**
|
||||
* Bug 1277803 - A test case for testing favicon loading across different first party domains.
|
||||
*/
|
||||
|
||||
const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/PlacesUtils.jsm");
|
||||
|
||||
const FIRST_PARTY_ONE = "example.com";
|
||||
const FIRST_PARTY_TWO = "example.org";
|
||||
const THIRD_PARTY = "mochi.test:8888";
|
||||
|
||||
const TEST_SITE_ONE = "http://" + FIRST_PARTY_ONE;
|
||||
const TEST_SITE_TWO = "http://" + FIRST_PARTY_TWO;
|
||||
const THIRD_PARTY_SITE = "http://" + THIRD_PARTY;
|
||||
const TEST_DIRECTORY = "/browser/browser/components/originattributes/test/browser/";
|
||||
|
||||
const TEST_PAGE = TEST_DIRECTORY + "file_favicon.html";
|
||||
const TEST_THIRD_PARTY_PAGE = TEST_DIRECTORY + "file_favicon_thirdParty.html";
|
||||
const TEST_CACHE_PAGE = TEST_DIRECTORY + "file_favicon_cache.html";
|
||||
|
||||
const FAVICON_URI = TEST_DIRECTORY + "file_favicon.png";
|
||||
const TEST_FAVICON_CACHE_URI = TEST_DIRECTORY + "file_favicon_cache.png";
|
||||
|
||||
let systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
|
||||
let makeURI = Cu.import("resource://gre/modules/BrowserUtils.jsm", {}).BrowserUtils.makeURI;
|
||||
|
||||
function clearAllImageCaches() {
|
||||
let tools = SpecialPowers.Cc["@mozilla.org/image/tools;1"]
|
||||
.getService(SpecialPowers.Ci.imgITools);
|
||||
let imageCache = tools.getImgCacheForDocument(window.document);
|
||||
imageCache.clearCache(true); // true=chrome
|
||||
imageCache.clearCache(false); // false=content
|
||||
}
|
||||
|
||||
function clearAllPlacesFavicons() {
|
||||
let faviconService = Cc["@mozilla.org/browser/favicon-service;1"]
|
||||
.getService(Ci.nsIFaviconService);
|
||||
|
||||
return new Promise(resolve => {
|
||||
let observer = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
if (aTopic === "places-favicons-expired") {
|
||||
resolve();
|
||||
Services.obs.removeObserver(observer, "places-favicons-expired", false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Services.obs.addObserver(observer, "places-favicons-expired", false);
|
||||
faviconService.expireAllFavicons();
|
||||
});
|
||||
}
|
||||
|
||||
function observeFavicon(aFirstPartyDomain, aExpectedCookie, aPageURI) {
|
||||
let faviconReqXUL = false;
|
||||
let faviconReqPlaces = false;
|
||||
let expectedPrincipal = Services.scriptSecurityManager
|
||||
.createCodebasePrincipal(aPageURI, { firstPartyDomain: aFirstPartyDomain });
|
||||
|
||||
return new Promise(resolve => {
|
||||
let observer = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
// Make sure that the topic is 'http-on-modify-request'.
|
||||
if (aTopic === "http-on-modify-request") {
|
||||
// We check the firstPartyDomain for the originAttributes of the loading
|
||||
// channel. All requests for the favicon should contain the correct
|
||||
// firstPartyDomain. There are two requests for a favicon loading, one
|
||||
// from the Places library and one from the XUL image. The difference
|
||||
// of them is the loading principal. The Places will use the content
|
||||
// principal and the XUL image will use the system principal.
|
||||
|
||||
let httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel);
|
||||
let reqLoadInfo = httpChannel.loadInfo;
|
||||
let loadingPrincipal = reqLoadInfo.loadingPrincipal;
|
||||
let triggeringPrincipal = reqLoadInfo.triggeringPrincipal;
|
||||
|
||||
// Make sure this is a favicon request.
|
||||
if (!httpChannel.URI.spec.endsWith(FAVICON_URI)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the first party domain.
|
||||
is(reqLoadInfo.originAttributes.firstPartyDomain, aFirstPartyDomain,
|
||||
"The loadInfo has correct first party domain");
|
||||
|
||||
if (loadingPrincipal.equals(systemPrincipal)) {
|
||||
faviconReqXUL = true;
|
||||
ok(triggeringPrincipal.equals(expectedPrincipal),
|
||||
"The triggeringPrincipal of favicon loading from XUL should be the content principal.");
|
||||
} else {
|
||||
faviconReqPlaces = true;
|
||||
ok(loadingPrincipal.equals(expectedPrincipal),
|
||||
"The loadingPrincipal of favicon loading from Places should be the content prinicpal");
|
||||
}
|
||||
|
||||
let faviconCookie = httpChannel.getRequestHeader("cookie");
|
||||
|
||||
is(faviconCookie, aExpectedCookie, "The cookie of the favicon loading is correct.");
|
||||
} else {
|
||||
ok(false, "Received unexpected topic: ", aTopic);
|
||||
}
|
||||
|
||||
if (faviconReqXUL && faviconReqPlaces) {
|
||||
Services.obs.removeObserver(observer, "http-on-modify-request", false);
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Services.obs.addObserver(observer, "http-on-modify-request", false);
|
||||
});
|
||||
}
|
||||
|
||||
function waitOnFaviconResponse(aFaviconURL) {
|
||||
return new Promise(resolve => {
|
||||
let observer = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
if (aTopic === "http-on-examine-response" ||
|
||||
aTopic === "http-on-examine-cached-response") {
|
||||
|
||||
let httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel);
|
||||
let loadInfo = httpChannel.loadInfo;
|
||||
|
||||
if (httpChannel.URI.spec !== aFaviconURL) {
|
||||
return;
|
||||
}
|
||||
|
||||
let result = {
|
||||
topic: aTopic,
|
||||
firstPartyDomain: loadInfo.originAttributes.firstPartyDomain
|
||||
};
|
||||
|
||||
resolve(result);
|
||||
Services.obs.removeObserver(observer, "http-on-examine-response", false);
|
||||
Services.obs.removeObserver(observer, "http-on-examine-cached-response", false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Services.obs.addObserver(observer, "http-on-examine-response", false);
|
||||
Services.obs.addObserver(observer, "http-on-examine-cached-response", false);
|
||||
});
|
||||
}
|
||||
|
||||
function waitOnFaviconLoaded(aFaviconURL) {
|
||||
return new Promise(resolve => {
|
||||
let observer = {
|
||||
onPageChanged(uri, attr, value, id) {
|
||||
|
||||
if (attr === Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON &&
|
||||
value === aFaviconURL) {
|
||||
resolve();
|
||||
PlacesUtils.history.removeObserver(observer, false);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
PlacesUtils.history.addObserver(observer, false);
|
||||
});
|
||||
}
|
||||
|
||||
function* openTab(aURL) {
|
||||
let tab = gBrowser.addTab(aURL);
|
||||
|
||||
// Select tab and make sure its browser is focused.
|
||||
gBrowser.selectedTab = tab;
|
||||
tab.ownerGlobal.focus();
|
||||
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
yield BrowserTestUtils.browserLoaded(browser);
|
||||
return {tab, browser};
|
||||
}
|
||||
|
||||
function* assignCookiesUnderFirstParty(aURL, aFirstParty, aCookieValue) {
|
||||
// Open a tab under the given aFirstParty, and this tab will have an
|
||||
// iframe which loads the aURL.
|
||||
let tabInfo = yield openTabInFirstParty(aURL, aFirstParty);
|
||||
|
||||
// Add cookies into the iframe.
|
||||
yield ContentTask.spawn(tabInfo.browser, aCookieValue, function* (value) {
|
||||
content.document.cookie = value;
|
||||
});
|
||||
|
||||
yield BrowserTestUtils.removeTab(tabInfo.tab);
|
||||
}
|
||||
|
||||
function* generateCookies(aThirdParty) {
|
||||
// we generate two different cookies for two first party domains.
|
||||
let cookies = [];
|
||||
cookies.push(Math.random().toString());
|
||||
cookies.push(Math.random().toString());
|
||||
|
||||
let firstSiteURL;
|
||||
let secondSiteURL;
|
||||
|
||||
if (aThirdParty) {
|
||||
// Add cookies into the third party site with different first party domain.
|
||||
firstSiteURL = THIRD_PARTY_SITE;
|
||||
secondSiteURL = THIRD_PARTY_SITE;
|
||||
} else {
|
||||
// Add cookies into sites.
|
||||
firstSiteURL = TEST_SITE_ONE;
|
||||
secondSiteURL = TEST_SITE_TWO;
|
||||
}
|
||||
|
||||
yield assignCookiesUnderFirstParty(firstSiteURL, TEST_SITE_ONE, cookies[0]);
|
||||
yield assignCookiesUnderFirstParty(secondSiteURL, TEST_SITE_TWO, cookies[1]);
|
||||
|
||||
return cookies;
|
||||
}
|
||||
|
||||
function* doTest(aTestPage, aExpectedCookies, aFaviconURL) {
|
||||
let firstPageURI = makeURI(TEST_SITE_ONE + aTestPage);
|
||||
let secondPageURI = makeURI(TEST_SITE_TWO + aTestPage);
|
||||
|
||||
// Start to observe the event of that favicon has been fully loaded.
|
||||
let promiseFaviconLoaded = waitOnFaviconLoaded(aFaviconURL);
|
||||
|
||||
// Start to observe the favicon requests earlier in case we miss it.
|
||||
let promiseObserveFavicon = observeFavicon(FIRST_PARTY_ONE, aExpectedCookies[0], firstPageURI);
|
||||
|
||||
// Open the tab for the first site.
|
||||
let tabInfo = yield openTab(TEST_SITE_ONE + aTestPage);
|
||||
|
||||
// Waiting until favicon requests are all made.
|
||||
yield promiseObserveFavicon;
|
||||
|
||||
// Waiting until favicon loaded.
|
||||
yield promiseFaviconLoaded;
|
||||
|
||||
// Close the tab.
|
||||
yield BrowserTestUtils.removeTab(tabInfo.tab);
|
||||
|
||||
// Start to observe the favicon requests earlier in case we miss it.
|
||||
promiseObserveFavicon = observeFavicon(FIRST_PARTY_TWO, aExpectedCookies[1], secondPageURI);
|
||||
|
||||
// Open the tab for the second site.
|
||||
tabInfo = yield openTab(TEST_SITE_TWO + aTestPage);
|
||||
|
||||
// Waiting until favicon requests are all made.
|
||||
yield promiseObserveFavicon;
|
||||
|
||||
yield BrowserTestUtils.removeTab(tabInfo.tab);
|
||||
}
|
||||
|
||||
add_task(function* setup() {
|
||||
// Make sure first party isolation is enabled.
|
||||
yield SpecialPowers.pushPrefEnv({"set": [
|
||||
["privacy.firstparty.isolate", true]
|
||||
]});
|
||||
});
|
||||
|
||||
// A clean up function to prevent affecting other tests.
|
||||
registerCleanupFunction(() => {
|
||||
// Clear all cookies.
|
||||
let cookieMgr = Cc["@mozilla.org/cookiemanager;1"]
|
||||
.getService(Ci.nsICookieManager);
|
||||
cookieMgr.removeAll();
|
||||
|
||||
// Clear all image caches and network caches.
|
||||
clearAllImageCaches();
|
||||
|
||||
let networkCache = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
|
||||
.getService(Ci.nsICacheStorageService);
|
||||
networkCache.clear();
|
||||
});
|
||||
|
||||
add_task(function* test_favicon_firstParty() {
|
||||
for (let testThirdParty of [false, true]) {
|
||||
// Clear all image caches and network caches before running the test.
|
||||
clearAllImageCaches();
|
||||
|
||||
let networkCache = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
|
||||
.getService(Ci.nsICacheStorageService);
|
||||
networkCache.clear();
|
||||
|
||||
// Clear Places favicon caches.
|
||||
yield clearAllPlacesFavicons();
|
||||
|
||||
let cookies = yield generateCookies(testThirdParty);
|
||||
|
||||
if (testThirdParty) {
|
||||
yield doTest(TEST_THIRD_PARTY_PAGE, cookies, THIRD_PARTY_SITE + FAVICON_URI);
|
||||
} else {
|
||||
yield doTest(TEST_PAGE, cookies, TEST_SITE_ONE + FAVICON_URI);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* test_favicon_cache_firstParty() {
|
||||
// Clear all image caches and network caches before running the test.
|
||||
clearAllImageCaches();
|
||||
|
||||
let networkCache = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
|
||||
.getService(Ci.nsICacheStorageService);
|
||||
networkCache.clear();
|
||||
|
||||
// Start to observer the event of that favicon has been fully loaded and cached.
|
||||
let promiseForFaviconLoaded = waitOnFaviconLoaded(THIRD_PARTY_SITE + TEST_FAVICON_CACHE_URI);
|
||||
|
||||
// Start to observer for the favicon response of the first tab.
|
||||
let responsePromise = waitOnFaviconResponse(THIRD_PARTY_SITE + TEST_FAVICON_CACHE_URI);
|
||||
|
||||
// Open the tab for the first site.
|
||||
let tabInfoA = yield openTab(TEST_SITE_ONE + TEST_CACHE_PAGE);
|
||||
|
||||
// Waiting for the favicon response.
|
||||
let response = yield responsePromise;
|
||||
|
||||
// Make sure the favicon is loaded through the network and its first party domain is correct.
|
||||
is(response.topic, "http-on-examine-response", "The favicon image should be loaded through network.");
|
||||
is(response.firstPartyDomain, FIRST_PARTY_ONE, "We should only observe the network response for the first first party.");
|
||||
|
||||
// Waiting until the favicon has been loaded and cached.
|
||||
yield promiseForFaviconLoaded;
|
||||
|
||||
// Open the tab again for checking the image cache is working correctly.
|
||||
let tabInfoB = yield openTab(TEST_SITE_ONE + TEST_CACHE_PAGE);
|
||||
|
||||
// Start to observe the favicon response, the second tab actually will not
|
||||
// make any network request since the favicon will be loaded by the cache for
|
||||
// both Places and XUL image. So here, we are going to observe the favicon
|
||||
// response for the third tab which opens with the second first party.
|
||||
let promiseForFaviconResponse = waitOnFaviconResponse(THIRD_PARTY_SITE + TEST_FAVICON_CACHE_URI);
|
||||
|
||||
// Open the tab for the second site.
|
||||
let tabInfoC = yield openTab(TEST_SITE_TWO + TEST_CACHE_PAGE);
|
||||
|
||||
// Wait for the favicon response. In this case, we suppose to catch the
|
||||
// response for the third tab but not the second tab since it will not
|
||||
// go through the network.
|
||||
response = yield promiseForFaviconResponse;
|
||||
|
||||
// Check that the favicon response has came from the network and it has the
|
||||
// correct first party domain.
|
||||
is(response.topic, "http-on-examine-response", "The favicon image should be loaded through network again.");
|
||||
is(response.firstPartyDomain, FIRST_PARTY_TWO, "We should only observe the network response for the second first party.");
|
||||
|
||||
yield BrowserTestUtils.removeTab(tabInfoA.tab);
|
||||
yield BrowserTestUtils.removeTab(tabInfoB.tab);
|
||||
yield BrowserTestUtils.removeTab(tabInfoC.tab);
|
||||
});
|
||||
|
|
@ -0,0 +1,257 @@
|
|||
/**
|
||||
* Bug 1277803 - A test caes for testing favicon loading across different userContextId.
|
||||
*/
|
||||
|
||||
const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/Promise.jsm");
|
||||
|
||||
const TEST_SITE = "http://example.net";
|
||||
const TEST_THIRD_PARTY_SITE = "http://mochi.test:8888";
|
||||
|
||||
const TEST_PAGE = TEST_SITE + "/browser/browser/components/originattributes/" +
|
||||
"test/browser/file_favicon.html";
|
||||
const FAVICON_URI = TEST_SITE + "/browser/browser/components/originattributes/" +
|
||||
"test/browser/file_favicon.png";
|
||||
const TEST_THIRD_PARTY_PAGE = "http://example.com/browser/browser/components/" +
|
||||
"originattributes/test/browser/file_favicon_thirdParty.html";
|
||||
const THIRD_PARTY_FAVICON_URI = TEST_THIRD_PARTY_SITE + "/browser/browser/components/" +
|
||||
"originattributes/test/browser/file_favicon.png";
|
||||
|
||||
const USER_CONTEXT_ID_PERSONAL = 1;
|
||||
const USER_CONTEXT_ID_WORK = 2;
|
||||
|
||||
let systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
|
||||
let makeURI = Cu.import("resource://gre/modules/BrowserUtils.jsm", {}).BrowserUtils.makeURI;
|
||||
|
||||
function clearAllImageCaches() {
|
||||
var tools = SpecialPowers.Cc["@mozilla.org/image/tools;1"]
|
||||
.getService(SpecialPowers.Ci.imgITools);
|
||||
var imageCache = tools.getImgCacheForDocument(window.document);
|
||||
imageCache.clearCache(true); // true=chrome
|
||||
imageCache.clearCache(false); // false=content
|
||||
}
|
||||
|
||||
function clearAllPlacesFavicons() {
|
||||
let faviconService = Cc["@mozilla.org/browser/favicon-service;1"]
|
||||
.getService(Ci.nsIFaviconService);
|
||||
|
||||
return new Promise(resolve => {
|
||||
let observer = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
if (aTopic === "places-favicons-expired") {
|
||||
resolve();
|
||||
Services.obs.removeObserver(observer, "places-favicons-expired", false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Services.obs.addObserver(observer, "places-favicons-expired", false);
|
||||
faviconService.expireAllFavicons();
|
||||
});
|
||||
}
|
||||
|
||||
function FaviconObserver(aUserContextId, aExpectedCookie, aPageURI, aFaviconURL) {
|
||||
this.reset(aUserContextId, aExpectedCookie, aPageURI, aFaviconURL);
|
||||
}
|
||||
|
||||
FaviconObserver.prototype = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
// Make sure that the topic is 'http-on-modify-request'.
|
||||
if (aTopic === "http-on-modify-request") {
|
||||
// We check the userContextId for the originAttributes of the loading
|
||||
// channel. All requests for the favicon should contain the correct
|
||||
// userContextId. There are two requests for a favicon loading, one
|
||||
// from the Places library and one from the XUL image. The difference
|
||||
// of them is the loading principal. The Places will use the content
|
||||
// principal and the XUL image will use the system principal.
|
||||
|
||||
let httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel);
|
||||
let reqLoadInfo = httpChannel.loadInfo;
|
||||
let loadingPrincipal;
|
||||
let triggeringPrincipal;
|
||||
|
||||
// Make sure this is a favicon request.
|
||||
if (httpChannel.URI.spec !== this._faviconURL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (reqLoadInfo) {
|
||||
loadingPrincipal = reqLoadInfo.loadingPrincipal;
|
||||
triggeringPrincipal = reqLoadInfo.triggeringPrincipal;
|
||||
}
|
||||
|
||||
// Check the userContextId.
|
||||
is(reqLoadInfo.originAttributes.userContextId, this._curUserContextId,
|
||||
"The loadInfo has correct userContextId");
|
||||
|
||||
if (loadingPrincipal.equals(systemPrincipal)) {
|
||||
this._faviconReqXUL = true;
|
||||
ok(triggeringPrincipal.equals(this._expectedPrincipal),
|
||||
"The triggeringPrincipal of favicon loading from XUL should be the content principal.");
|
||||
} else {
|
||||
this._faviconReqPlaces = true;
|
||||
ok(loadingPrincipal.equals(this._expectedPrincipal),
|
||||
"The loadingPrincipal of favicon loading from Places should be the content prinicpal");
|
||||
}
|
||||
|
||||
let faviconCookie = httpChannel.getRequestHeader("cookie");
|
||||
|
||||
is(faviconCookie, this._expectedCookie, "The cookie of the favicon loading is correct.");
|
||||
} else {
|
||||
ok(false, "Received unexpected topic: ", aTopic);
|
||||
}
|
||||
|
||||
if (this._faviconReqXUL && this._faviconReqPlaces) {
|
||||
this._faviconLoaded.resolve();
|
||||
}
|
||||
},
|
||||
|
||||
reset(aUserContextId, aExpectedCookie, aPageURI, aFaviconURL) {
|
||||
this._curUserContextId = aUserContextId;
|
||||
this._expectedCookie = aExpectedCookie;
|
||||
this._expectedPrincipal = Services.scriptSecurityManager
|
||||
.createCodebasePrincipal(aPageURI, { userContextId: aUserContextId });
|
||||
this._faviconReqXUL = false;
|
||||
this._faviconReqPlaces = false;
|
||||
this._faviconURL = aFaviconURL;
|
||||
this._faviconLoaded = new Promise.defer();
|
||||
},
|
||||
|
||||
get promise() {
|
||||
return this._faviconLoaded.promise;
|
||||
}
|
||||
};
|
||||
|
||||
function waitOnFaviconLoaded(aFaviconURL) {
|
||||
return new Promise(resolve => {
|
||||
let observer = {
|
||||
onPageChanged(uri, attr, value, id) {
|
||||
|
||||
if (attr === Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON &&
|
||||
value === aFaviconURL) {
|
||||
resolve();
|
||||
PlacesUtils.history.removeObserver(observer, false);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
PlacesUtils.history.addObserver(observer, false);
|
||||
});
|
||||
}
|
||||
|
||||
function* generateCookies(aHost) {
|
||||
// we generate two different cookies for two userContextIds.
|
||||
let cookies = [];
|
||||
cookies.push(Math.random().toString());
|
||||
cookies.push(Math.random().toString());
|
||||
|
||||
// Then, we add cookies into the site for 'personal' and 'work'.
|
||||
let tabInfoA = yield openTabInUserContext(aHost, USER_CONTEXT_ID_PERSONAL);
|
||||
let tabInfoB = yield openTabInUserContext(aHost, USER_CONTEXT_ID_WORK);
|
||||
|
||||
yield ContentTask.spawn(tabInfoA.browser, cookies[0], function* (value) {
|
||||
content.document.cookie = value;
|
||||
});
|
||||
|
||||
yield ContentTask.spawn(tabInfoB.browser, cookies[1], function* (value) {
|
||||
content.document.cookie = value;
|
||||
});
|
||||
|
||||
yield BrowserTestUtils.removeTab(tabInfoA.tab);
|
||||
yield BrowserTestUtils.removeTab(tabInfoB.tab);
|
||||
|
||||
return cookies;
|
||||
}
|
||||
|
||||
function* doTest(aTestPage, aFaviconHost, aFaviconURL) {
|
||||
let cookies = yield generateCookies(aFaviconHost);
|
||||
let pageURI = makeURI(aTestPage);
|
||||
|
||||
// Create the observer object for observing request channels of the personal
|
||||
// container.
|
||||
let observer = new FaviconObserver(USER_CONTEXT_ID_PERSONAL, cookies[0], pageURI, aFaviconURL);
|
||||
|
||||
// Add the observer earlier in case we miss it.
|
||||
let promiseWaitOnFaviconLoaded = waitOnFaviconLoaded(aFaviconURL);
|
||||
|
||||
Services.obs.addObserver(observer, "http-on-modify-request", false);
|
||||
|
||||
// Open the tab with the personal container.
|
||||
let tabInfo = yield openTabInUserContext(aTestPage, USER_CONTEXT_ID_PERSONAL);
|
||||
|
||||
// Waiting for favicon requests are all made.
|
||||
yield observer.promise;
|
||||
// Waiting for favicon loaded.
|
||||
yield promiseWaitOnFaviconLoaded;
|
||||
|
||||
// Close the tab.
|
||||
yield BrowserTestUtils.removeTab(tabInfo.tab);
|
||||
|
||||
// Reset the observer for observing requests for the work container.
|
||||
observer.reset(USER_CONTEXT_ID_WORK, cookies[1], pageURI, aFaviconURL);
|
||||
tabInfo = yield openTabInUserContext(aTestPage, USER_CONTEXT_ID_WORK);
|
||||
|
||||
// Waiting for favicon requests are all made.
|
||||
yield observer.promise;
|
||||
|
||||
Services.obs.removeObserver(observer, "http-on-modify-request", false);
|
||||
|
||||
yield BrowserTestUtils.removeTab(tabInfo.tab);
|
||||
}
|
||||
|
||||
add_task(function* setup() {
|
||||
// Make sure userContext is enabled.
|
||||
yield SpecialPowers.pushPrefEnv({"set": [
|
||||
["privacy.userContext.enabled", true]
|
||||
]});
|
||||
});
|
||||
|
||||
// A clean up function to prevent affecting other tests.
|
||||
registerCleanupFunction(() => {
|
||||
// Clear all cookies.
|
||||
let cookieMgr = Cc["@mozilla.org/cookiemanager;1"]
|
||||
.getService(Ci.nsICookieManager);
|
||||
cookieMgr.removeAll();
|
||||
|
||||
// Clear all image caches and network caches.
|
||||
clearAllImageCaches();
|
||||
|
||||
let networkCache = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
|
||||
.getService(Ci.nsICacheStorageService);
|
||||
networkCache.clear();
|
||||
|
||||
// Clear Places favicon caches.
|
||||
clearAllPlacesFavicons();
|
||||
});
|
||||
|
||||
add_task(function* test_favicon_userContextId() {
|
||||
// Clear all image caches before running the test.
|
||||
clearAllImageCaches();
|
||||
|
||||
// Clear all network caches.
|
||||
let networkCache = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
|
||||
.getService(Ci.nsICacheStorageService);
|
||||
networkCache.clear();
|
||||
|
||||
// Clear Places favicon caches.
|
||||
yield clearAllPlacesFavicons();
|
||||
|
||||
yield doTest(TEST_PAGE, TEST_SITE, FAVICON_URI);
|
||||
});
|
||||
|
||||
add_task(function* test_thirdPartyFavicon_userContextId() {
|
||||
// Clear all image caches before running the test.
|
||||
clearAllImageCaches();
|
||||
|
||||
// Clear all network caches.
|
||||
let networkCache = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
|
||||
.getService(Ci.nsICacheStorageService);
|
||||
networkCache.clear();
|
||||
|
||||
// Clear Places favicon caches.
|
||||
yield clearAllPlacesFavicons();
|
||||
|
||||
yield doTest(TEST_THIRD_PARTY_PAGE, TEST_THIRD_PARTY_SITE, THIRD_PARTY_FAVICON_URI);
|
||||
});
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
const BASE_URL = "http://mochi.test:8888/browser/browser/components/originattributes/test/browser/";
|
||||
const BASE_DOMAIN = "mochi.test";
|
||||
|
||||
add_task(function* setup() {
|
||||
Services.prefs.setBoolPref("privacy.firstparty.isolate", true);
|
||||
registerCleanupFunction(function () {
|
||||
Services.prefs.clearUserPref("privacy.firstparty.isolate");
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Test for the top-level document and child iframes should have the
|
||||
* firstPartyDomain attribute.
|
||||
*/
|
||||
add_task(function* principal_test() {
|
||||
let tab = gBrowser.addTab(BASE_URL + "test_firstParty.html");
|
||||
yield BrowserTestUtils.browserLoaded(tab.linkedBrowser, true, function (url) {
|
||||
return url == BASE_URL + "test_firstParty.html";
|
||||
});
|
||||
|
||||
yield ContentTask.spawn(tab.linkedBrowser, { firstPartyDomain: BASE_DOMAIN }, function* (attrs) {
|
||||
info("document principal: " + content.document.nodePrincipal.origin);
|
||||
Assert.equal(docShell.getOriginAttributes().firstPartyDomain, "",
|
||||
"top-level docShell shouldn't have firstPartyDomain attribute.");
|
||||
Assert.equal(content.document.nodePrincipal.originAttributes.firstPartyDomain,
|
||||
attrs.firstPartyDomain, "The document should have firstPartyDomain");
|
||||
|
||||
for (let i = 1; i < 4; i++) {
|
||||
let iframe = content.document.getElementById("iframe" + i);
|
||||
info("iframe principal: " + iframe.contentDocument.nodePrincipal.origin);
|
||||
Assert.equal(iframe.frameLoader.docShell.getOriginAttributes().firstPartyDomain,
|
||||
attrs.firstPartyDomain, "iframe's docshell should have firstPartyDomain");
|
||||
Assert.equal(iframe.contentDocument.nodePrincipal.originAttributes.firstPartyDomain,
|
||||
attrs.firstPartyDomain, "iframe should have firstPartyDomain");
|
||||
}
|
||||
});
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
|
||||
/**
|
||||
* Test for the cookie jars of the top-level document and child iframe should be
|
||||
* isolated by firstPartyDomain.
|
||||
*/
|
||||
add_task(function* cookie_test() {
|
||||
let tab = gBrowser.addTab(BASE_URL + "test_firstParty_cookie.html");
|
||||
yield BrowserTestUtils.browserLoaded(tab.linkedBrowser, true);
|
||||
|
||||
let iter = Services.cookies.enumerator;
|
||||
let count = 0;
|
||||
while (iter.hasMoreElements()) {
|
||||
count++;
|
||||
let cookie = iter.getNext().QueryInterface(Ci.nsICookie2);
|
||||
Assert.equal(cookie.value, "foo", "Cookie value should be foo");
|
||||
Assert.equal(cookie.originAttributes.firstPartyDomain, BASE_DOMAIN, "Cookie's origin attributes should be " + BASE_DOMAIN);
|
||||
}
|
||||
|
||||
// one cookie is from requesting test.js from top-level doc, and the other from
|
||||
// requesting test2.js from iframe test2.html.
|
||||
Assert.equal(count, 2, "Should have two cookies");
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
|
||||
/**
|
||||
* Test for after redirect, the top-level document should update the firstPartyDomain
|
||||
* attribute. However if the redirect is happening on the iframe, the attribute
|
||||
* should remain the same.
|
||||
*/
|
||||
add_task(function* redirect_test() {
|
||||
let tab = gBrowser.addTab(BASE_URL + "test_firstParty_http_redirect.html");
|
||||
yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
yield ContentTask.spawn(tab.linkedBrowser, { firstPartyDomain: "example.com" }, function* (attrs) {
|
||||
info("document principal: " + content.document.nodePrincipal.origin);
|
||||
info("document uri: " + content.document.documentURI);
|
||||
|
||||
Assert.equal(content.document.documentURI, "http://example.com/browser/browser/components/originattributes/test/browser/dummy.html",
|
||||
"The page should have been redirected to http://example.com/browser/browser/components/originattributes/test/browser/dummy.html");
|
||||
Assert.equal(content.document.nodePrincipal.originAttributes.firstPartyDomain,
|
||||
attrs.firstPartyDomain, "The document should have firstPartyDomain");
|
||||
});
|
||||
|
||||
// Since this is a HTML redirect, we wait until the final page is loaded.
|
||||
let tab2 = gBrowser.addTab(BASE_URL + "test_firstParty_html_redirect.html");
|
||||
yield BrowserTestUtils.browserLoaded(tab2.linkedBrowser, false, function(url) {
|
||||
return url == "http://example.com/";
|
||||
});
|
||||
|
||||
yield ContentTask.spawn(tab2.linkedBrowser, { firstPartyDomain: "example.com" }, function* (attrs) {
|
||||
info("2nd tab document principal: " + content.document.nodePrincipal.origin);
|
||||
info("2nd tab document uri: " + content.document.documentURI);
|
||||
Assert.equal(content.document.documentURI, "http://example.com/",
|
||||
"The page should have been redirected to http://example.com");
|
||||
Assert.equal(content.document.nodePrincipal.originAttributes.firstPartyDomain,
|
||||
attrs.firstPartyDomain, "The document should have firstPartyDomain");
|
||||
});
|
||||
|
||||
let tab3 = gBrowser.addTab(BASE_URL + "test_firstParty_iframe_http_redirect.html");
|
||||
yield BrowserTestUtils.browserLoaded(tab3.linkedBrowser, true, function(url) {
|
||||
return url == (BASE_URL + "test_firstParty_iframe_http_redirect.html");
|
||||
});
|
||||
|
||||
// This redirect happens on the iframe, so unlike the two redirect tests above,
|
||||
// the firstPartyDomain should still stick to the current top-level document,
|
||||
// which is mochi.test.
|
||||
yield ContentTask.spawn(tab3.linkedBrowser, { firstPartyDomain: "mochi.test" }, function* (attrs) {
|
||||
let iframe = content.document.getElementById("iframe1");
|
||||
info("iframe document principal: " + iframe.contentDocument.nodePrincipal.origin);
|
||||
info("iframe document uri: " + iframe.contentDocument.documentURI);
|
||||
|
||||
Assert.equal(iframe.contentDocument.documentURI, "http://example.com/browser/browser/components/originattributes/test/browser/dummy.html",
|
||||
"The page should have been redirected to http://example.com/browser/browser/components/originattributes/test/browser/dummy.html");
|
||||
Assert.equal(iframe.contentDocument.nodePrincipal.originAttributes.firstPartyDomain,
|
||||
attrs.firstPartyDomain, "The iframe should have firstPartyDomain: " + attrs.firstPartyDomain);
|
||||
});
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
gBrowser.removeTab(tab2);
|
||||
gBrowser.removeTab(tab3);
|
||||
});
|
||||
|
||||
/**
|
||||
* Test for postMessage between document and iframe.
|
||||
*/
|
||||
add_task(function* postMessage_test() {
|
||||
let tab = gBrowser.addTab(BASE_URL + "test_firstParty_postMessage.html");
|
||||
|
||||
// The top-level page will post a message to its child iframe, and wait for
|
||||
// another message from the iframe, once it receives the message, it will
|
||||
// create another iframe, dummy.html.
|
||||
// So we wait until dummy.html is loaded
|
||||
yield BrowserTestUtils.browserLoaded(tab.linkedBrowser, true, function (url) {
|
||||
return url == BASE_URL + "dummy.html";
|
||||
});
|
||||
|
||||
yield ContentTask.spawn(tab.linkedBrowser, {}, function* () {
|
||||
info("document principal: " + content.document.nodePrincipal.origin);
|
||||
let value = content.document.getElementById("message").textContent;
|
||||
Assert.equal(value, "OK");
|
||||
});
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
|
||||
/**
|
||||
* When the web page calls window.open, the new window should have the same
|
||||
* firstPartyDomain attribute.
|
||||
*/
|
||||
add_task(function* openWindow_test() {
|
||||
Services.prefs.setIntPref("browser.link.open_newwindow", 2);
|
||||
registerCleanupFunction(function () {
|
||||
Services.prefs.clearUserPref("browser.link.open_newwindow");
|
||||
});
|
||||
|
||||
let tab = gBrowser.addTab(BASE_URL + "window.html");
|
||||
let win = yield BrowserTestUtils.waitForNewWindow();
|
||||
|
||||
yield ContentTask.spawn(win.gBrowser.selectedBrowser, { firstPartyDomain: "mochi.test" }, function* (attrs) {
|
||||
Assert.equal(docShell.getOriginAttributes().firstPartyDomain, attrs.firstPartyDomain,
|
||||
"window.open() should have firstPartyDomain attribute");
|
||||
Assert.equal(content.document.nodePrincipal.originAttributes.firstPartyDomain,
|
||||
attrs.firstPartyDomain, "The document should have firstPartyDomain");
|
||||
|
||||
let iframe = content.document.getElementById("iframe1");
|
||||
Assert.equal(iframe.frameLoader.docShell.getOriginAttributes().firstPartyDomain,
|
||||
attrs.firstPartyDomain, "iframe's docshell should have firstPartyDomain");
|
||||
Assert.equal(iframe.contentDocument.nodePrincipal.originAttributes.firstPartyDomain,
|
||||
attrs.firstPartyDomain, "iframe should have firstPartyDomain");
|
||||
});
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
yield BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
let Cu = Components.utils;
|
||||
let {HttpServer} = Cu.import("resource://testing-common/httpd.js", {});
|
||||
|
||||
let server = new HttpServer();
|
||||
server.registerPathHandler('/file.html', fileHandler);
|
||||
server.start(-1);
|
||||
|
||||
let BASE_URI = 'http://localhost:' + server.identity.primaryPort;
|
||||
let FILE_URI = BASE_URI + '/file.html';
|
||||
|
||||
let credentialQueue = [];
|
||||
|
||||
// Ask the user agent for authorization.
|
||||
function fileHandler(metadata, response) {
|
||||
if (!metadata.hasHeader("Authorization")) {
|
||||
response.setStatusLine(metadata.httpVersion, 401, "Unauthorized");
|
||||
response.setHeader("WWW-Authenticate", "Basic realm=\"User Visible Realm\"");
|
||||
return;
|
||||
}
|
||||
|
||||
// This will be "account:password" encoded in base64.
|
||||
credentialQueue.push(metadata.getHeader("Authorization"));
|
||||
|
||||
response.setStatusLine(metadata.httpVersion, 200, "OK");
|
||||
response.setHeader("Content-Type", "text/html", false);
|
||||
let body = "<html><body></body></html>";
|
||||
response.bodyOutputStream.write(body, body.length);
|
||||
}
|
||||
|
||||
function onCommonDialogLoaded(subject) {
|
||||
// Submit random account and password
|
||||
let dialog = subject.Dialog;
|
||||
dialog.ui.loginTextbox.setAttribute("value", Math.random());
|
||||
dialog.ui.password1Textbox.setAttribute("value", Math.random());
|
||||
dialog.ui.button0.click();
|
||||
}
|
||||
|
||||
Services.obs.addObserver(onCommonDialogLoaded, "common-dialog-loaded", false);
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
Services.obs.removeObserver(onCommonDialogLoaded, "common-dialog-loaded");
|
||||
server.stop(() => {
|
||||
server = null;
|
||||
});
|
||||
});
|
||||
|
||||
function getResult() {
|
||||
// If two targets are isolated, they should get different credentials.
|
||||
// Otherwise, the credentials will be cached and therefore the same.
|
||||
return credentialQueue.shift();
|
||||
}
|
||||
|
||||
IsolationTestTools.runTests(FILE_URI, getResult);
|
||||
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Bug 1264572 - A test case for image cache isolation.
|
||||
*/
|
||||
|
||||
requestLongerTimeout(2);
|
||||
|
||||
let Cu = Components.utils;
|
||||
let {HttpServer} = Cu.import("resource://testing-common/httpd.js", {});
|
||||
|
||||
const NUM_ISOLATION_LOADS = 2;
|
||||
const NUM_CACHED_LOADS = 1;
|
||||
|
||||
let gHits = 0;
|
||||
|
||||
let server = new HttpServer();
|
||||
server.registerPathHandler('/image.png', imageHandler);
|
||||
server.registerPathHandler('/file.html', fileHandler);
|
||||
server.start(-1);
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
server.stop(() => {
|
||||
server = null;
|
||||
});
|
||||
});
|
||||
|
||||
let BASE_URI = 'http://localhost:' + server.identity.primaryPort;
|
||||
let IMAGE_URI = BASE_URI + '/image.png';
|
||||
let FILE_URI = BASE_URI + '/file.html';
|
||||
|
||||
function imageHandler(metadata, response) {
|
||||
info('XXX: loading image from server');
|
||||
gHits++;
|
||||
response.setHeader("Cache-Control", "max-age=10000", false);
|
||||
response.setStatusLine(metadata.httpVersion, 200, "OK");
|
||||
response.setHeader("Content-Type", "image/png", false);
|
||||
var body = "iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAAEUlEQVQImWP4z8AAQTAamQkAhpcI+DeMzFcAAAAASUVORK5CYII=";
|
||||
response.bodyOutputStream.write(body, body.length);
|
||||
}
|
||||
|
||||
function fileHandler(metadata, response) {
|
||||
response.setStatusLine(metadata.httpVersion, 200, "OK");
|
||||
response.setHeader("Content-Type", "text/html", false);
|
||||
let body = `<html><body><image src=${IMAGE_URI}></body></html>`;
|
||||
response.bodyOutputStream.write(body, body.length);
|
||||
}
|
||||
|
||||
function doBefore() {
|
||||
// reset hit counter
|
||||
info('XXX resetting gHits');
|
||||
gHits = 0;
|
||||
info('XXX clearing image cache');
|
||||
let imageCache = Cc["@mozilla.org/image/tools;1"]
|
||||
.getService(Ci.imgITools)
|
||||
.getImgCacheForDocument(null);
|
||||
imageCache.clearCache(true);
|
||||
imageCache.clearCache(false);
|
||||
info('XXX clearning network cache');
|
||||
let networkCache = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
|
||||
.getService(Ci.nsICacheStorageService);
|
||||
networkCache.clear();
|
||||
}
|
||||
|
||||
// the test function does nothing on purpose.
|
||||
function doTest(aBrowser) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// the check function
|
||||
function doCheck(shouldIsolate, a, b) {
|
||||
// if we're doing first party isolation and the image cache isolation is
|
||||
// working, then gHits should be 2 because the image would have been loaded
|
||||
// one per first party domain. if first party isolation is disabled, then
|
||||
// gHits should be 1 since there would be one image load from the server and
|
||||
// one load from the image cache.
|
||||
info(`XXX check: gHits == ${gHits}, shouldIsolate == ${shouldIsolate}`);
|
||||
return shouldIsolate ? gHits == NUM_ISOLATION_LOADS
|
||||
: gHits == NUM_CACHED_LOADS;
|
||||
}
|
||||
|
||||
IsolationTestTools.runTests(FILE_URI, doTest, doCheck, doBefore);
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
* Bug 1264567 - A test case for localStorage isolation.
|
||||
*/
|
||||
|
||||
const TEST_PAGE = "http://mochi.test:8888/browser/browser/components/" +
|
||||
"originattributes/test/browser/file_firstPartyBasic.html";
|
||||
|
||||
// Use a random key so we don't access it in later tests.
|
||||
const key = Math.random().toString();
|
||||
|
||||
// Define the testing function
|
||||
function* doTest(aBrowser) {
|
||||
return yield ContentTask.spawn(aBrowser, key, function (key) {
|
||||
let value = content.localStorage.getItem(key);
|
||||
if (value === null) {
|
||||
// No value is found, so we create one.
|
||||
value = Math.random().toString();
|
||||
content.localStorage.setItem(key, value);
|
||||
}
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
IsolationTestTools.runTests(TEST_PAGE, doTest);
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
* Bug 1264593 - A test case for the shared worker by first party isolation.
|
||||
*/
|
||||
|
||||
const TEST_DOMAIN = "http://example.net/";
|
||||
const TEST_PATH = TEST_DOMAIN + "browser/browser/components/originattributes/test/browser/";
|
||||
const TEST_PAGE = TEST_PATH + "file_sharedworker.html";
|
||||
|
||||
function* getResultFromSharedworker(aBrowser) {
|
||||
let response = yield ContentTask.spawn(aBrowser, null, function* () {
|
||||
let worker = new content.SharedWorker("file_sharedworker.js", "isolationSharedWorkerTest");
|
||||
|
||||
let result = yield new Promise(resolve => {
|
||||
worker.port.onmessage = function (e) {
|
||||
content.document.getElementById("display").innerHTML = e.data;
|
||||
resolve(e.data);
|
||||
};
|
||||
});
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
IsolationTestTools.runTests(TEST_PAGE, getResultFromSharedworker);
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Dummy test page</title>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"></meta>
|
||||
</head>
|
||||
<body>
|
||||
<p>Dummy test page</p>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
<title>Page broadcast channel creator for first party isolation</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="display" style="white-space:pre; font-family:monospace; display:inline;"></div>
|
||||
<iframe id="iframe" src="file_broadcastChanneliFrame.html"></iframe>>
|
||||
<script type="text/javascript;version=1.7">
|
||||
let bc = new BroadcastChannel("testBroadcastChannel");
|
||||
bc.onmessage = function (e) {
|
||||
document.getElementById("display").innerHTML = e.data;
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
<title>Page broadcast channel responder for first party isolation</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="display" style="white-space:pre; font-family:monospace; display:inline;"></div>
|
||||
<script type="text/javascript;version=1.7">
|
||||
let bc = new BroadcastChannel("testBroadcastChannel");
|
||||
bc.onmessage = function (e) {
|
||||
window.parent.postMessage(e.data, "*");
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="http://example.net/browser/browser/components/originattributes/test/browser/file_thirdPartyChild.link.css">
|
||||
<link rel="preconnect" href="http://example.net">
|
||||
</head>
|
||||
<body>
|
||||
<div>file_cache.html</div>
|
||||
|
||||
<iframe src="http://example.net/browser/browser/components/originattributes/test/browser/file_thirdPartyChild.iframe.html">
|
||||
</iframe>
|
||||
|
||||
<script src="http://example.net/browser/browser/components/originattributes/test/browser/file_thirdPartyChild.script.js">
|
||||
</script>
|
||||
|
||||
<img src="http://example.net/browser/browser/components/originattributes/test/browser/file_thirdPartyChild.img.png">
|
||||
|
||||
<embed src="http://example.net/browser/browser/components/originattributes/test/browser/file_thirdPartyChild.embed.png">
|
||||
|
||||
<object data="http://example.net/browser/browser/components/originattributes/test/browser/file_thirdPartyChild.object.png"
|
||||
type="image/png"></object>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<title>Favicon Test for originAttributes</title>
|
||||
<link rel="icon" type="image/png" href="file_favicon.png" />
|
||||
</head>
|
||||
<body>
|
||||
Favicon!!
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 344 B |
|
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-cache
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<title>Favicon Test for originAttributes</title>
|
||||
<link rel="icon" type="image/png" href="http://mochi.test:8888/browser/browser/components/originattributes/test/browser/file_favicon_cache.png" />
|
||||
</head>
|
||||
<body>
|
||||
Third Party Favicon!!
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 344 B |
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<title>Favicon Test for originAttributes</title>
|
||||
<link rel="icon" type="image/png" href="http://mochi.test:8888/browser/browser/components/originattributes/test/browser/file_favicon.png" />
|
||||
</head>
|
||||
<body>
|
||||
Third Party Favicon!!
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>First Party Isolation Tests</title>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
<title>Page SharedWorker creator for first party isolation</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="display" style="white-space:pre; font-family:monospace; display:inline;"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
self.randomValue = Math.random();
|
||||
|
||||
/* global onconnect:true */
|
||||
|
||||
onconnect = function (e) {
|
||||
let port = e.ports[0];
|
||||
port.postMessage(self.randomValue);
|
||||
port.start();
|
||||
};
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 95 B |
|
|
@ -0,0 +1,8 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
|
||||
<!-- The child page, used by browser_cache.js -->
|
||||
<body>
|
||||
<div>thirdPartyChild.fetch.html</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
|
||||
<!-- The child page, used by browser_cache.js -->
|
||||
<body>
|
||||
<div>thirdPartyChild.html</div>
|
||||
<script>
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "http://example.net/browser/browser/components/originattributes/test/browser/file_thirdPartyChild.xhr.html", true);
|
||||
xhr.send();
|
||||
var worker = new Worker("http://example.net/browser/browser/components/originattributes/test/browser/file_thirdPartyChild.worker.js");
|
||||
var sharedWorker = new SharedWorker("http://example.net/browser/browser/components/originattributes/test/browser/file_thirdPartyChild.sharedworker.js");
|
||||
|
||||
fetch("file_thirdPartyChild.fetch.html", {cache: "force-cache"} );
|
||||
fetch(new Request("file_thirdPartyChild.request.html"), {cache: "force-cache"} );
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 95 B |
|
|
@ -0,0 +1 @@
|
|||
// dummy script, to be called by self.importScripts(...)
|
||||
|
|
@ -0,0 +1 @@
|
|||
/* Dummy CSS file, used by browser_cache.js. */
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 95 B |
|
|
@ -0,0 +1,8 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
|
||||
<!-- The child page, used by browser_cache.js -->
|
||||
<body>
|
||||
<div>thirdPartyChild.request.html</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1 @@
|
|||
// Dummy child script, used by browser_cache.js
|
||||
|
|
@ -0,0 +1 @@
|
|||
// dummy file
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
WEBVTT FILE
|
||||
|
||||
1
|
||||
00:00:00.500 --> 00:00:02.000 D:vertical A:start
|
||||
blah blah blah
|
||||
|
||||
2
|
||||
00:00:02.500 --> 00:00:04.300
|
||||
this is a test
|
||||
|
||||
3
|
||||
00:00:05.000 --> 00:00:07.000
|
||||
one more line
|
||||
Binary file not shown.
|
|
@ -0,0 +1,8 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
|
||||
<!-- The child page, used by browser_cache.js -->
|
||||
<body>
|
||||
<div>thirdPartyChild.worker.fetch.html</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "http://example.net/browser/browser/components/originattributes/test/browser/file_thirdPartyChild.worker.xhr.html", true);
|
||||
xhr.send();
|
||||
|
||||
fetch("http://example.net/browser/browser/components/originattributes/test/browser/file_thirdPartyChild.worker.fetch.html", {cache: "force-cache"} );
|
||||
var myRequest = new Request("http://example.net/browser/browser/components/originattributes/test/browser/file_thirdPartyChild.worker.request.html");
|
||||
fetch(myRequest, {cache: "force-cache"} );
|
||||
|
||||
self.importScripts("http://example.net/browser/browser/components/originattributes/test/browser/file_thirdPartyChild.import.js");
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
|
||||
<!-- The child page, used by browser_cache.js -->
|
||||
<body>
|
||||
<div>thirdPartyChild.worker.request.html</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
|
||||
<!-- The child page, used by browser_cache.js -->
|
||||
<body>
|
||||
<div>thirdPartyChild.worker.xhr.html</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
|
||||
<!-- The child page, used by browser_cache.js -->
|
||||
<body>
|
||||
<div>thirdPartyChild.html</div>
|
||||
</body>
|
||||
</html>
|
||||
365
browser/components/originattributes/test/browser/head.js
Normal file
365
browser/components/originattributes/test/browser/head.js
Normal file
|
|
@ -0,0 +1,365 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
'use strict';
|
||||
|
||||
const TEST_URL_PATH = "/browser/browser/components/originattributes/test/browser/";
|
||||
|
||||
// The flags of test modes.
|
||||
const TEST_MODE_FIRSTPARTY = 0;
|
||||
const TEST_MODE_NO_ISOLATION = 1;
|
||||
const TEST_MODE_CONTAINERS = 2;
|
||||
|
||||
// The name of each mode.
|
||||
const TEST_MODE_NAMES = [ "first party isolation",
|
||||
"no isolation",
|
||||
"containers" ];
|
||||
|
||||
// The frame types.
|
||||
const TEST_TYPE_FRAME = 0;
|
||||
const TEST_TYPE_IFRAME = 1;
|
||||
|
||||
// The default frame setting.
|
||||
const DEFAULT_FRAME_SETTING = [ TEST_TYPE_IFRAME ];
|
||||
|
||||
let gFirstPartyBasicPage = TEST_URL_PATH + "file_firstPartyBasic.html";
|
||||
|
||||
/**
|
||||
* Add a tab for the given url with the specific user context id.
|
||||
*
|
||||
* @param aURL
|
||||
* The url of the page.
|
||||
* @param aUserContextId
|
||||
* The user context id for this tab.
|
||||
*
|
||||
* @return tab - The tab object of this tab.
|
||||
* browser - The browser object of this tab.
|
||||
*/
|
||||
function* openTabInUserContext(aURL, aUserContextId) {
|
||||
// Open the tab in the correct userContextId.
|
||||
let tab = gBrowser.addTab(aURL, {userContextId: aUserContextId});
|
||||
|
||||
// Select tab and make sure its browser is focused.
|
||||
gBrowser.selectedTab = tab;
|
||||
tab.ownerGlobal.focus();
|
||||
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
yield BrowserTestUtils.browserLoaded(browser);
|
||||
return {tab, browser};
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a tab for a page with the given first party domain. This page will have
|
||||
* an iframe which is loaded with the given url by default or you could specify
|
||||
* a frame setting to create nested frames. And this function will also modify
|
||||
* the 'content' in the ContentTask to the target frame's window object.
|
||||
*
|
||||
* @param aURL
|
||||
* The url of the iframe.
|
||||
* @param aFirstPartyDomain
|
||||
* The first party domain.
|
||||
* @param aFrameSetting
|
||||
* This setting controls how frames are organized within the page. The
|
||||
* setting is an array of frame types, the first item indicates the
|
||||
* frame type (iframe or frame) of the first layer of the frame structure,
|
||||
* and the second item indicates the second layer, and so on. The aURL will
|
||||
* be loaded at the deepest layer. This is optional.
|
||||
*
|
||||
* @return tab - The tab object of this tab.
|
||||
* browser - The browser object of this tab.
|
||||
*/
|
||||
function* openTabInFirstParty(aURL, aFirstPartyDomain,
|
||||
aFrameSetting = DEFAULT_FRAME_SETTING) {
|
||||
|
||||
// If the first party domain ends with '/', we remove it.
|
||||
if (aFirstPartyDomain.endsWith('/')) {
|
||||
aFirstPartyDomain = aFirstPartyDomain.slice(0, -1);
|
||||
}
|
||||
|
||||
let basicPageURL = aFirstPartyDomain + gFirstPartyBasicPage;
|
||||
|
||||
// Open the tab for the basic first party page.
|
||||
let tab = gBrowser.addTab(basicPageURL);
|
||||
|
||||
// Select tab and make sure its browser is focused.
|
||||
gBrowser.selectedTab = tab;
|
||||
tab.ownerGlobal.focus();
|
||||
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
yield BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
let pageArgs = { url: aURL,
|
||||
frames: aFrameSetting,
|
||||
typeFrame: TEST_TYPE_FRAME,
|
||||
typeIFrame: TEST_TYPE_IFRAME,
|
||||
basicFrameSrc: basicPageURL};
|
||||
|
||||
// Create the frame structure.
|
||||
yield ContentTask.spawn(browser, pageArgs, function* (arg) {
|
||||
let typeFrame = arg.typeFrame;
|
||||
let typeIFrame = arg.typeIFrame;
|
||||
|
||||
// Redefine the 'content' for allowing us to change its target, and making
|
||||
// ContentTask.spawn can directly work on the frame element.
|
||||
this.frameWindow = content;
|
||||
|
||||
Object.defineProperty(this, "content", {
|
||||
get: () => this.frameWindow
|
||||
});
|
||||
|
||||
let frameElement;
|
||||
let numOfLayers = 0;
|
||||
|
||||
for (let type of arg.frames) {
|
||||
let document = content.document;
|
||||
numOfLayers++;
|
||||
|
||||
if (type === typeFrame) {
|
||||
// Add a frameset which carries the frame element.
|
||||
let frameSet = document.createElement('frameset');
|
||||
frameSet.cols = "50%,50%";
|
||||
|
||||
let frame = document.createElement('frame');
|
||||
let dummyFrame = document.createElement('frame');
|
||||
|
||||
frameSet.appendChild(frame);
|
||||
frameSet.appendChild(dummyFrame);
|
||||
|
||||
document.body.appendChild(frameSet);
|
||||
|
||||
frameElement = frame;
|
||||
} else if (type === typeIFrame) {
|
||||
// Add an iframe.
|
||||
let iframe = document.createElement('iframe');
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
frameElement = iframe;
|
||||
} else {
|
||||
ok(false, "Invalid frame type.");
|
||||
break;
|
||||
}
|
||||
|
||||
// Wait for the frame to be loaded.
|
||||
yield new Promise(done => {
|
||||
frameElement.addEventListener("load", function loadEnd() {
|
||||
frameElement.removeEventListener("load", loadEnd, true);
|
||||
done();
|
||||
}, true);
|
||||
|
||||
// If it is the deepest layer, we load the target URL. Otherwise, we
|
||||
// load a basic page.
|
||||
if (numOfLayers === arg.frames.length) {
|
||||
frameElement.setAttribute("src", arg.url);
|
||||
} else {
|
||||
frameElement.setAttribute("src", arg.basicFrameSrc);
|
||||
}
|
||||
});
|
||||
|
||||
// Redirect the 'content' to the frame's window.
|
||||
this.frameWindow = frameElement.contentWindow;
|
||||
}
|
||||
});
|
||||
|
||||
return {tab, browser};
|
||||
}
|
||||
|
||||
this.IsolationTestTools = {
|
||||
/**
|
||||
* Adds isolation tests for first party isolation, no isolation
|
||||
* and containers respectively.
|
||||
*
|
||||
* @param aTask
|
||||
* The testing task which will be run in different settings.
|
||||
*/
|
||||
_add_task(aTask) {
|
||||
add_task(function* addTaskForIsolationTests() {
|
||||
let testSettings = [
|
||||
{ mode: TEST_MODE_FIRSTPARTY,
|
||||
skip: false,
|
||||
prefs: [["privacy.firstparty.isolate", true]]
|
||||
},
|
||||
{ mode: TEST_MODE_NO_ISOLATION,
|
||||
skip: false,
|
||||
prefs: [["privacy.firstparty.isolate", false]]
|
||||
},
|
||||
{ mode: TEST_MODE_CONTAINERS,
|
||||
skip: false,
|
||||
prefs: [["privacy.userContext.enabled", true]]
|
||||
},
|
||||
];
|
||||
|
||||
// Add test tasks.
|
||||
for (let testSetting of testSettings) {
|
||||
IsolationTestTools._addTaskForMode(testSetting.mode,
|
||||
testSetting.prefs,
|
||||
testSetting.skip,
|
||||
aTask);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_addTaskForMode(aMode, aPref, aSkip, aTask) {
|
||||
if (aSkip) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_task(function* () {
|
||||
info("Starting the test for " + TEST_MODE_NAMES[aMode]);
|
||||
|
||||
// Before run this task, reset the preferences first.
|
||||
yield SpecialPowers.flushPrefEnv();
|
||||
|
||||
// Make sure preferences are set properly.
|
||||
yield SpecialPowers.pushPrefEnv({"set": aPref});
|
||||
|
||||
yield SpecialPowers.pushPrefEnv({"set": [["dom.ipc.processCount", 1]]});
|
||||
|
||||
yield aTask(aMode);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a tab with the given tab setting, this will open different types of
|
||||
* tabs according to the given test mode. A tab setting means a isolation
|
||||
* target in different test mode; a tab setting indicates a first party
|
||||
* domain when testing the first party isolation, it is a user context
|
||||
* id when testing containers.
|
||||
*
|
||||
* @param aMode
|
||||
* The test mode which decides what type of tabs will be opened.
|
||||
* @param aURL
|
||||
* The url which is going to open.
|
||||
* @param aTabSettingObj
|
||||
* The tab setting object includes 'firstPartyDomain' for the first party
|
||||
* domain and 'userContextId' for Containers.
|
||||
* @param aFrameSetting
|
||||
* This setting controls how frames are organized within the page. The
|
||||
* setting is an array of frame types, the first item indicates the
|
||||
* frame type (iframe or frame) of the first layer of the frame structure,
|
||||
* and the second item indicates the second layer, and so on. The aURL
|
||||
* will be loaded at the deepest layer. This is optional.
|
||||
*
|
||||
* @return tab - The tab object of this tab.
|
||||
* browser - The browser object of this tab.
|
||||
*/
|
||||
_addTab(aMode, aURL, aTabSettingObj, aFrameSetting) {
|
||||
if (aMode === TEST_MODE_CONTAINERS) {
|
||||
return openTabInUserContext(aURL, aTabSettingObj.userContextId);
|
||||
}
|
||||
|
||||
return openTabInFirstParty(aURL, aTabSettingObj.firstPartyDomain,
|
||||
aFrameSetting);
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Run isolation tests. The framework will run tests with standard combinations
|
||||
* of prefs and tab settings, and checks whether the isolation is working.
|
||||
*
|
||||
* @param aURL
|
||||
* The URL of the page that will be tested or an object contains 'url',
|
||||
* the tested page, 'firstFrameSetting' for the frame setting of the first
|
||||
* tab, and 'secondFrameSetting' for the second tab.
|
||||
* @param aGetResultFuncs
|
||||
* An array of functions or a single function which are responsible for
|
||||
* returning the isolation result back to the framework for further checking.
|
||||
* Each of these functions will be provided the browser object of the tab,
|
||||
* that allows modifying or fetchings results from the page content.
|
||||
* @param aCompareResultFunc
|
||||
* An optional function which allows modifying the way how does framework
|
||||
* check results. This function will be provided a boolean to indicate
|
||||
* the isolation is no or off and two results. This function should return
|
||||
* a boolean to tell that whether isolation is working. If this function
|
||||
* is not given, the framework will take case checking by itself.
|
||||
* @param aBeforeFunc
|
||||
* An optional function which is called before any tabs are created so
|
||||
* that the test case can set up/reset local state.
|
||||
* @param aGetResultImmediately
|
||||
* An optional boolean to ensure we get results before the next tab is opened.
|
||||
*/
|
||||
runTests(aURL, aGetResultFuncs, aCompareResultFunc, aBeforeFunc,
|
||||
aGetResultImmediately) {
|
||||
let pageURL;
|
||||
let firstFrameSetting;
|
||||
let secondFrameSetting;
|
||||
|
||||
// Request a longer timeout since the test will run a test for three times
|
||||
// with different settings. Thus, one test here represents three tests.
|
||||
// For this reason, we triple the timeout.
|
||||
requestLongerTimeout(3);
|
||||
|
||||
if (typeof aURL === "string") {
|
||||
pageURL = aURL;
|
||||
} else if (typeof aURL === "object") {
|
||||
pageURL = aURL.url;
|
||||
firstFrameSetting = aURL.firstFrameSetting;
|
||||
secondFrameSetting = aURL.secondFrameSetting;
|
||||
}
|
||||
|
||||
if (!Array.isArray(aGetResultFuncs)) {
|
||||
aGetResultFuncs = [aGetResultFuncs];
|
||||
}
|
||||
|
||||
let tabSettings = [
|
||||
{ firstPartyDomain: "http://example.com", userContextId: 1},
|
||||
{ firstPartyDomain: "http://example.org", userContextId: 2}
|
||||
];
|
||||
|
||||
this._add_task(function* (aMode) {
|
||||
let tabSettingA = 0;
|
||||
|
||||
for (let tabSettingB of [0, 1]) {
|
||||
// Give the test a chance to set up before each case is run.
|
||||
if (aBeforeFunc) {
|
||||
yield aBeforeFunc(aMode);
|
||||
}
|
||||
|
||||
// Create Tabs.
|
||||
let tabInfoA = yield IsolationTestTools._addTab(aMode,
|
||||
pageURL,
|
||||
tabSettings[tabSettingA],
|
||||
firstFrameSetting);
|
||||
let resultsA = [];
|
||||
if (aGetResultImmediately) {
|
||||
for (let getResultFunc of aGetResultFuncs) {
|
||||
resultsA.push(yield getResultFunc(tabInfoA.browser));
|
||||
}
|
||||
}
|
||||
let tabInfoB = yield IsolationTestTools._addTab(aMode,
|
||||
pageURL,
|
||||
tabSettings[tabSettingB],
|
||||
secondFrameSetting);
|
||||
let i = 0;
|
||||
for (let getResultFunc of aGetResultFuncs) {
|
||||
// Fetch results from tabs.
|
||||
let resultA = aGetResultImmediately ? resultsA[i++] :
|
||||
yield getResultFunc(tabInfoA.browser);
|
||||
let resultB = yield getResultFunc(tabInfoB.browser);
|
||||
|
||||
// Compare results.
|
||||
let result = false;
|
||||
let shouldIsolate = (aMode !== TEST_MODE_NO_ISOLATION) &&
|
||||
tabSettingA !== tabSettingB;
|
||||
if (aCompareResultFunc) {
|
||||
result = yield aCompareResultFunc(shouldIsolate, resultA, resultB);
|
||||
} else {
|
||||
result = shouldIsolate ? resultA !== resultB :
|
||||
resultA === resultB;
|
||||
}
|
||||
|
||||
let msg = `Testing ${TEST_MODE_NAMES[aMode]} for ` +
|
||||
`isolation ${shouldIsolate ? "on" : "off"} with TabSettingA ` +
|
||||
`${tabSettingA} and tabSettingB ${tabSettingB}` +
|
||||
`, resultA = ${resultA}, resultB = ${resultB}`;
|
||||
|
||||
ok(result, msg);
|
||||
}
|
||||
|
||||
// Close Tabs.
|
||||
yield BrowserTestUtils.removeTab(tabInfoA.tab);
|
||||
yield BrowserTestUtils.removeTab(tabInfoB.tab);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
20
browser/components/originattributes/test/browser/test.html
Normal file
20
browser/components/originattributes/test/browser/test.html
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1260931</title>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script>
|
||||
window.onmessage = function (evt) {
|
||||
if (evt.data != "HI") {
|
||||
return;
|
||||
}
|
||||
|
||||
window.parent.postMessage("OK", "http://mochi.test:8888");
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
Hello World.
|
||||
</body>
|
||||
</html>
|
||||
1
browser/components/originattributes/test/browser/test.js
Normal file
1
browser/components/originattributes/test/browser/test.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
var i = 1;
|
||||
|
|
@ -0,0 +1 @@
|
|||
Set-Cookie: test=foo
|
||||
12
browser/components/originattributes/test/browser/test2.html
Normal file
12
browser/components/originattributes/test/browser/test2.html
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1260931</title>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script src="test2.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
Hello World.
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1 @@
|
|||
var i = 1;
|
||||
|
|
@ -0,0 +1 @@
|
|||
Set-Cookie: test2=foo
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Test for Bug 1260931</title>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<iframe id="iframe1" src="http://example.com"></iframe>
|
||||
<iframe id="iframe2" sandbox="" src="http://example.com"></iframe>
|
||||
<iframe id="iframe3" sandbox="allow-same-origin" src="http://example.com"></iframe>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1260931</title>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script src="test.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
Hello World.
|
||||
<iframe id="iframe1" src="test2.html"></iframe>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf8" http-equiv="refresh" content="0; url=http://example.com/"/>
|
||||
<title>Test for Bug 1260931</title>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Test for Bug 1260931</title>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
HTTP 302 Found
|
||||
Location: http://example.com/browser/browser/components/originattributes/test/browser/dummy.html
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Test for Bug 1260931</title>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<iframe id="iframe1" src="test_firstParty_http_redirect.html"></iframe>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Test for Bug 1260931</title>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<script>
|
||||
function onload() {
|
||||
let iframe1 = document.getElementById("iframe1");
|
||||
iframe1.contentWindow.postMessage("HI", "http://mochi.test:8888");
|
||||
}
|
||||
|
||||
window.onmessage = function (evt) {
|
||||
document.getElementById("message").textContent = evt.data;
|
||||
|
||||
let iframe2 = document.createElement("iframe");
|
||||
iframe2.src = "dummy.html";
|
||||
document.body.appendChild(iframe2);
|
||||
};
|
||||
</script>
|
||||
<body onload="onload()">
|
||||
<div>
|
||||
<iframe id="iframe1" src="test.html"></iframe>
|
||||
<span id="message"></span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
13
browser/components/originattributes/test/browser/window.html
Normal file
13
browser/components/originattributes/test/browser/window.html
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title>Page creating a popup</title>
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
var w = window.open();
|
||||
w.document.body.innerHTML = "<iframe id='iframe1' src='data:text/plain,test2'></iframe>";
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
// Wait for a string to be posted to this worker.
|
||||
// Create a blob containing this string, and then
|
||||
// post back a blob URL pointing to the blob.
|
||||
self.addEventListener("message", function (e) {
|
||||
try {
|
||||
var blobURL = URL.createObjectURL(new Blob([e.data]));
|
||||
postMessage({ blobURL });
|
||||
} catch (e) {
|
||||
postMessage({ error: e.message });
|
||||
}
|
||||
}, false);
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
// Wait for a blob URL to be posted to this worker.
|
||||
// Obtain the blob, and read the string contained in it.
|
||||
// Post back the string.
|
||||
|
||||
var postStringInBlob = function (blobObject) {
|
||||
var fileReader = new FileReaderSync();
|
||||
var result = fileReader.readAsText(blobObject);
|
||||
postMessage(result);
|
||||
};
|
||||
|
||||
self.addEventListener("message", function (e) {
|
||||
if ("error" in e.data) {
|
||||
postMessage(e.data);
|
||||
return;
|
||||
}
|
||||
var blobURL = e.data.blobURL,
|
||||
xhr = new XMLHttpRequest();
|
||||
try {
|
||||
xhr.open("GET", blobURL, true);
|
||||
xhr.onload = function () {
|
||||
postStringInBlob(xhr.response);
|
||||
};
|
||||
xhr.onerror = function () {
|
||||
postMessage({ error: "xhr error" });
|
||||
};
|
||||
xhr.responseType = "blob";
|
||||
xhr.send();
|
||||
} catch (e) {
|
||||
postMessage({ error: e.message });
|
||||
}
|
||||
}, false);
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<h1>I'm just a support file</h1>
|
||||
<p>I get loaded to do permission testing.</p>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
file_empty.html
|
||||
|
||||
[test_permissions_api.html]
|
||||
|
|
@ -0,0 +1,207 @@
|
|||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Permissions API</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<pre id="test"></pre>
|
||||
<script type="application/javascript;version=1.8">
|
||||
/*globals SpecialPowers, SimpleTest, is, ok, */
|
||||
'use strict';
|
||||
|
||||
const {
|
||||
UNKNOWN_ACTION,
|
||||
PROMPT_ACTION,
|
||||
ALLOW_ACTION,
|
||||
DENY_ACTION
|
||||
} = SpecialPowers.Ci.nsIPermissionManager;
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const PERMISSIONS = [{
|
||||
name: 'geolocation',
|
||||
type: 'geo'
|
||||
}, {
|
||||
name: 'notifications',
|
||||
type: 'desktop-notification'
|
||||
}, {
|
||||
name: 'push',
|
||||
type: 'desktop-notification'
|
||||
}, ];
|
||||
|
||||
const UNSUPPORTED_PERMISSIONS = [
|
||||
'foobarbaz', // Not in spec, for testing only.
|
||||
'midi',
|
||||
];
|
||||
|
||||
// Create a closure, so that tests are run on the correct window object.
|
||||
function createPermissionTester(aWindow) {
|
||||
return {
|
||||
setPermissions(allow) {
|
||||
const permissions = PERMISSIONS.map(({ type }) => {
|
||||
return {
|
||||
type,
|
||||
allow,
|
||||
'context': aWindow.document
|
||||
};
|
||||
});
|
||||
return new Promise((resolve) => {
|
||||
SpecialPowers.popPermissions(() => {
|
||||
SpecialPowers.pushPermissions(permissions, resolve);
|
||||
});
|
||||
});
|
||||
},
|
||||
revokePermissions() {
|
||||
const promisesToRevoke = PERMISSIONS.map(({ name }) => {
|
||||
return aWindow.navigator.permissions
|
||||
.revoke({ name })
|
||||
.then(
|
||||
({ state }) => is(state, 'prompt', `correct state for '${name}'`),
|
||||
() => ok(false, `revoke should not have rejected for '${name}'`)
|
||||
);
|
||||
});
|
||||
return Promise.all(promisesToRevoke);
|
||||
},
|
||||
revokeUnsupportedPermissions() {
|
||||
const promisesToRevoke = UNSUPPORTED_PERMISSIONS.map(({ name }) => {
|
||||
return aWindow.navigator.permissions
|
||||
.revoke({ name })
|
||||
.then(
|
||||
() => ok(false, `revoke should not have resolved for '${name}'`),
|
||||
error => is(error.name, 'TypeError', `revoke should have thrown TypeError for '${name}'`)
|
||||
);
|
||||
});
|
||||
return Promise.all(promisesToRevoke);
|
||||
},
|
||||
checkPermissions(state) {
|
||||
const promisesToQuery = PERMISSIONS.map(({ name }) => {
|
||||
return aWindow.navigator.permissions
|
||||
.query({ name })
|
||||
.then(
|
||||
() => is(state, state, `correct state for '${name}'`),
|
||||
() => ok(false, `query should not have rejected for '${name}'`)
|
||||
);
|
||||
});
|
||||
return Promise.all(promisesToQuery);
|
||||
},
|
||||
checkUnsupportedPermissions() {
|
||||
const promisesToQuery = UNSUPPORTED_PERMISSIONS.map(({ name }) => {
|
||||
return aWindow.navigator.permissions
|
||||
.query({ name })
|
||||
.then(
|
||||
() => ok(false, `query should not have resolved for '${name}'`),
|
||||
error => {
|
||||
is(error.name, 'TypeError',
|
||||
`query should have thrown TypeError for '${name}'`);
|
||||
}
|
||||
);
|
||||
});
|
||||
return Promise.all(promisesToQuery);
|
||||
},
|
||||
promiseStateChanged(name, state) {
|
||||
return aWindow.navigator.permissions
|
||||
.query({ name })
|
||||
.then(status => {
|
||||
return new Promise( resolve => {
|
||||
status.onchange = () => {
|
||||
status.onchange = null;
|
||||
is(status.state, state, `state changed for '${name}'`);
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
},
|
||||
() => ok(false, `query should not have rejected for '${name}'`));
|
||||
},
|
||||
testStatusOnChange() {
|
||||
return new Promise((resolve) => {
|
||||
SpecialPowers.popPermissions(() => {
|
||||
const permission = 'geolocation';
|
||||
const promiseGranted = this.promiseStateChanged(permission, 'granted');
|
||||
this.setPermissions(ALLOW_ACTION);
|
||||
promiseGranted.then(() => {
|
||||
const promisePrompt = this.promiseStateChanged(permission, 'prompt');
|
||||
SpecialPowers.popPermissions();
|
||||
return promisePrompt;
|
||||
}).then(resolve);
|
||||
});
|
||||
});
|
||||
},
|
||||
testInvalidQuery() {
|
||||
return aWindow.navigator.permissions
|
||||
.query({ name: 'invalid' })
|
||||
.then(
|
||||
() => ok(false, 'invalid query should not have resolved'),
|
||||
() => ok(true, 'invalid query should have rejected')
|
||||
);
|
||||
},
|
||||
testInvalidRevoke() {
|
||||
return aWindow.navigator.permissions
|
||||
.revoke({ name: 'invalid' })
|
||||
.then(
|
||||
() => ok(false, 'invalid revoke should not have resolved'),
|
||||
() => ok(true, 'invalid revoke should have rejected')
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function enablePrefs() {
|
||||
const ops = {
|
||||
'set': [
|
||||
['dom.permissions.revoke.enable', true],
|
||||
['privacy.firstparty.isolate', true],
|
||||
],
|
||||
};
|
||||
return SpecialPowers.pushPrefEnv(ops);
|
||||
}
|
||||
|
||||
function createIframe() {
|
||||
return new Promise((resolve) => {
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.src = 'file_empty.html';
|
||||
iframe.onload = () => resolve(iframe.contentWindow);
|
||||
document.body.appendChild(iframe);
|
||||
});
|
||||
}
|
||||
debugger;
|
||||
window.onload = () => {
|
||||
enablePrefs()
|
||||
.then(createIframe)
|
||||
.then(createPermissionTester)
|
||||
.then((tester) => {
|
||||
return tester
|
||||
.checkUnsupportedPermissions()
|
||||
.then(() => tester.setPermissions(UNKNOWN_ACTION))
|
||||
.then(() => tester.checkPermissions('prompt'))
|
||||
.then(() => tester.setPermissions(PROMPT_ACTION))
|
||||
.then(() => tester.checkPermissions('prompt'))
|
||||
.then(() => tester.setPermissions(ALLOW_ACTION))
|
||||
.then(() => tester.checkPermissions('granted'))
|
||||
.then(() => tester.setPermissions(DENY_ACTION))
|
||||
.then(() => tester.checkPermissions('denied'))
|
||||
.then(() => tester.testStatusOnChange())
|
||||
.then(() => tester.testInvalidQuery())
|
||||
.then(() => tester.revokeUnsupportedPermissions())
|
||||
.then(() => tester.revokePermissions())
|
||||
.then(() => tester.checkPermissions('prompt'))
|
||||
.then(() => tester.testInvalidRevoke());
|
||||
})
|
||||
.then(SimpleTest.finish)
|
||||
.catch((e) => {
|
||||
ok(false, `Unexpected error ${e}`);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue