mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 05:11:16 +00:00
Bug 1778492 - Add an origin trial for coep: credentialless r=emilio,necko-reviewers,kershaw
Differential Revision: https://phabricator.services.mozilla.com/D151381
This commit is contained in:
parent
bda035b7f5
commit
288cbe9f46
@ -3998,7 +3998,8 @@ nsresult Document::InitCOEP(nsIChannel* aChannel) {
|
||||
|
||||
nsILoadInfo::CrossOriginEmbedderPolicy policy =
|
||||
nsILoadInfo::EMBEDDER_POLICY_NULL;
|
||||
if (NS_SUCCEEDED(intChannel->GetResponseEmbedderPolicy(&policy))) {
|
||||
if (NS_SUCCEEDED(intChannel->GetResponseEmbedderPolicy(
|
||||
mTrials.IsEnabled(OriginTrial::CoepCredentialless), &policy))) {
|
||||
mEmbedderPolicy = Some(policy);
|
||||
}
|
||||
|
||||
@ -6874,6 +6875,15 @@ void Document::SetHeaderData(nsAtom* aHeaderField, const nsAString& aData) {
|
||||
|
||||
if (aHeaderField == nsGkAtoms::origin_trial) {
|
||||
mTrials.UpdateFromToken(aData, NodePrincipal());
|
||||
if (mTrials.IsEnabled(OriginTrial::CoepCredentialless)) {
|
||||
InitCOEP(mChannel);
|
||||
|
||||
WindowContext* ctx = GetWindowContext();
|
||||
MOZ_ASSERT(ctx);
|
||||
if (mEmbedderPolicy) {
|
||||
Unused << ctx->SetEmbedderPolicy(mEmbedderPolicy.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (aHeaderField == nsGkAtoms::headerDefaultStyle) {
|
||||
|
@ -4711,6 +4711,18 @@ nsDOMWindowUtils::IsCssPropertyRecordedInUseCounter(const nsACString& aPropName,
|
||||
return knownProp ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::IsCoepCredentialless(bool* aResult) {
|
||||
Document* doc = GetDocument();
|
||||
if (!doc) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*aResult = IsCoepCredentiallessEnabled(
|
||||
doc->Trials().IsEnabled(OriginTrial::CoepCredentialless));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::GetLayersId(uint64_t* aOutLayersId) {
|
||||
nsIWidget* widget = GetWidget();
|
||||
|
@ -1,2 +1,23 @@
|
||||
[DEFAULT]
|
||||
[browser_blobFromFile.js]
|
||||
[browser_origin_trial_coep_credentialless_fetch_1.js]
|
||||
support-files =
|
||||
open_credentialless_document.sjs
|
||||
store_header.sjs
|
||||
[browser_origin_trial_coep_credentialless_fetch_2.js]
|
||||
support-files =
|
||||
open_credentialless_document.sjs
|
||||
store_header.sjs
|
||||
[browser_origin_trial_coep_credentialless_fetch_3.js]
|
||||
support-files =
|
||||
open_credentialless_document.sjs
|
||||
store_header.sjs
|
||||
[browser_origin_trial_coep_credentialless_worker.js]
|
||||
support-files =
|
||||
open_credentialless_document.sjs
|
||||
store_header.sjs
|
||||
credentialless_worker.sjs
|
||||
[browser_origin_trial_coep_credentialless_cache.js]
|
||||
support-files =
|
||||
open_credentialless_document.sjs
|
||||
credentialless_resource.sjs
|
||||
|
@ -0,0 +1,142 @@
|
||||
const TOP_LEVEL_URL =
|
||||
getRootDirectory(gTestPath).replace(
|
||||
"chrome://mochitests/content",
|
||||
"https://example.com"
|
||||
) + "open_credentialless_document.sjs";
|
||||
|
||||
const SAME_ORIGIN = "https://example.com";
|
||||
const CROSS_ORIGIN = "https://test1.example.com";
|
||||
|
||||
const USE_CREDENTIALLESS = true;
|
||||
const NO_CREDENTIALLESS = false;
|
||||
|
||||
const RESOURCE_URL =
|
||||
getRootDirectory(gTestPath).replace(
|
||||
"chrome://mochitests/content",
|
||||
"https://test1.example.com"
|
||||
) + "credentialless_resource.sjs";
|
||||
|
||||
async function store(storer, url, requestCredentialMode) {
|
||||
await SpecialPowers.spawn(
|
||||
storer.linkedBrowser,
|
||||
[url, requestCredentialMode],
|
||||
async function(url, requestCredentialMode) {
|
||||
const cache = await content.caches.open("v1");
|
||||
const fetchRequest = new content.Request(url, {
|
||||
mode: "no-cors",
|
||||
credentials: requestCredentialMode,
|
||||
});
|
||||
|
||||
const fetchResponse = await content.fetch(fetchRequest);
|
||||
content.wrappedJSObject.console.log(fetchResponse.headers);
|
||||
await cache.put(fetchRequest, fetchResponse);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
async function retrieve(retriever, resourceURL) {
|
||||
return await SpecialPowers.spawn(
|
||||
retriever.linkedBrowser,
|
||||
[resourceURL],
|
||||
async function(url) {
|
||||
const cache = await content.caches.open("v1");
|
||||
try {
|
||||
await cache.match(url);
|
||||
return "retrieved";
|
||||
} catch (error) {
|
||||
return "error";
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
async function testCache(
|
||||
storer,
|
||||
storeRequestCredentialMode,
|
||||
resourceCOEP,
|
||||
retriever,
|
||||
expectation
|
||||
) {
|
||||
const resourceURL = RESOURCE_URL + "?" + resourceCOEP;
|
||||
|
||||
await store(storer, resourceURL, storeRequestCredentialMode);
|
||||
const result = await retrieve(retriever, resourceURL);
|
||||
|
||||
is(result, expectation);
|
||||
}
|
||||
|
||||
add_task(async function() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["browser.tabs.remote.coep.credentialless", false],
|
||||
["dom.origin-trials.enabled", true],
|
||||
["dom.origin-trials.test-key.enabled", true],
|
||||
],
|
||||
});
|
||||
|
||||
const noneTab = await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
TOP_LEVEL_URL
|
||||
);
|
||||
const requireCorpTab = await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
TOP_LEVEL_URL + "?requirecorp"
|
||||
);
|
||||
const credentiallessTab = await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
TOP_LEVEL_URL + "?credentialless"
|
||||
);
|
||||
|
||||
await testCache(noneTab, "include", "", noneTab, "retrieved");
|
||||
await testCache(noneTab, "include", "", credentiallessTab, "error");
|
||||
await testCache(noneTab, "omit", "", credentiallessTab, "retrieved");
|
||||
await testCache(
|
||||
noneTab,
|
||||
"include",
|
||||
"corp_cross_origin",
|
||||
credentiallessTab,
|
||||
"retrieved"
|
||||
);
|
||||
await testCache(noneTab, "include", "", requireCorpTab, "error");
|
||||
await testCache(
|
||||
noneTab,
|
||||
"include",
|
||||
"corp_cross_origin",
|
||||
requireCorpTab,
|
||||
"retrieved"
|
||||
);
|
||||
await testCache(credentiallessTab, "include", "", noneTab, "retrieved");
|
||||
await testCache(
|
||||
credentiallessTab,
|
||||
"include",
|
||||
"",
|
||||
credentiallessTab,
|
||||
"retrieved"
|
||||
);
|
||||
await testCache(credentiallessTab, "include", "", requireCorpTab, "error");
|
||||
await testCache(
|
||||
requireCorpTab,
|
||||
"include",
|
||||
"corp_cross_origin",
|
||||
noneTab,
|
||||
"retrieved"
|
||||
);
|
||||
await testCache(
|
||||
requireCorpTab,
|
||||
"include",
|
||||
"corp_cross_origin",
|
||||
credentiallessTab,
|
||||
"retrieved"
|
||||
);
|
||||
await testCache(
|
||||
requireCorpTab,
|
||||
"include",
|
||||
"corp_cross_origin",
|
||||
requireCorpTab,
|
||||
"retrieved"
|
||||
);
|
||||
|
||||
await BrowserTestUtils.removeTab(noneTab);
|
||||
await BrowserTestUtils.removeTab(requireCorpTab);
|
||||
await BrowserTestUtils.removeTab(credentiallessTab);
|
||||
});
|
@ -0,0 +1,134 @@
|
||||
const TOP_LEVEL_URL =
|
||||
getRootDirectory(gTestPath).replace(
|
||||
"chrome://mochitests/content",
|
||||
"https://example.com"
|
||||
) + "open_credentialless_document.sjs";
|
||||
|
||||
const SAME_ORIGIN = "https://example.com";
|
||||
const CROSS_ORIGIN = "https://test1.example.com";
|
||||
|
||||
const USE_CREDENTIALLESS = true;
|
||||
const NO_CREDENTIALLESS = false;
|
||||
|
||||
const GET_STATE_URL =
|
||||
getRootDirectory(gTestPath).replace(
|
||||
"chrome://mochitests/content",
|
||||
"https://example.com"
|
||||
) + "store_header.sjs?getstate";
|
||||
|
||||
async function addCookieToOrigin(origin) {
|
||||
const fetchRequestURL =
|
||||
getRootDirectory(gTestPath).replace("chrome://mochitests/content", origin) +
|
||||
"store_header.sjs?addcookie";
|
||||
|
||||
const addcookieTab = await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
fetchRequestURL
|
||||
);
|
||||
|
||||
await SpecialPowers.spawn(addcookieTab.linkedBrowser, [], async function() {
|
||||
content.document.cookie = "coep=credentialless; SameSite=None; Secure";
|
||||
});
|
||||
await BrowserTestUtils.removeTab(addcookieTab);
|
||||
}
|
||||
|
||||
async function testOrigin(
|
||||
fetchOrigin,
|
||||
isCredentialless,
|
||||
fetchRequestMode,
|
||||
fetchRequestCrendentials,
|
||||
expectedCookieResult
|
||||
) {
|
||||
let topLevelUrl = TOP_LEVEL_URL;
|
||||
if (isCredentialless) {
|
||||
topLevelUrl += "?credentialless";
|
||||
}
|
||||
|
||||
const noCredentiallessTab = await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
topLevelUrl
|
||||
);
|
||||
|
||||
const fetchRequestURL =
|
||||
getRootDirectory(gTestPath).replace(
|
||||
"chrome://mochitests/content",
|
||||
fetchOrigin
|
||||
) + "store_header.sjs?checkheader";
|
||||
|
||||
await SpecialPowers.spawn(
|
||||
noCredentiallessTab.linkedBrowser,
|
||||
[
|
||||
fetchRequestURL,
|
||||
fetchRequestMode,
|
||||
fetchRequestCrendentials,
|
||||
GET_STATE_URL,
|
||||
expectedCookieResult,
|
||||
],
|
||||
async function(
|
||||
fetchRequestURL,
|
||||
fetchRequestMode,
|
||||
fetchRequestCrendentials,
|
||||
getStateURL,
|
||||
expectedCookieResult
|
||||
) {
|
||||
// When store_header.sjs receives this request, it will store
|
||||
// whether it has received the cookie as a shared state.
|
||||
await content.fetch(fetchRequestURL, {
|
||||
mode: fetchRequestMode,
|
||||
credentials: fetchRequestCrendentials,
|
||||
});
|
||||
|
||||
// This request is used to get the saved state from the
|
||||
// previous fetch request.
|
||||
const response = await content.fetch(getStateURL, {
|
||||
mode: "cors",
|
||||
});
|
||||
const text = await response.text();
|
||||
is(text, expectedCookieResult);
|
||||
}
|
||||
);
|
||||
|
||||
await BrowserTestUtils.removeTab(noCredentiallessTab);
|
||||
}
|
||||
|
||||
async function doTest(
|
||||
origin,
|
||||
fetchRequestMode,
|
||||
fetchRequestCrendentials,
|
||||
expectedCookieResultForNoCredentialless,
|
||||
expectedCookieResultForCredentialless
|
||||
) {
|
||||
await testOrigin(
|
||||
origin,
|
||||
USE_CREDENTIALLESS,
|
||||
fetchRequestMode,
|
||||
fetchRequestCrendentials,
|
||||
expectedCookieResultForCredentialless
|
||||
);
|
||||
await testOrigin(
|
||||
origin,
|
||||
NO_CREDENTIALLESS,
|
||||
fetchRequestMode,
|
||||
fetchRequestCrendentials,
|
||||
expectedCookieResultForNoCredentialless
|
||||
);
|
||||
}
|
||||
|
||||
add_task(async function() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["browser.tabs.remote.coep.credentialless", false],
|
||||
["dom.origin-trials.enabled", true],
|
||||
["dom.origin-trials.test-key.enabled", true],
|
||||
],
|
||||
});
|
||||
|
||||
await addCookieToOrigin(SAME_ORIGIN);
|
||||
await addCookieToOrigin(CROSS_ORIGIN);
|
||||
|
||||
// Cookies never sent with omit
|
||||
await doTest(SAME_ORIGIN, "no-cors", "omit", "noCookie", "noCookie");
|
||||
await doTest(SAME_ORIGIN, "cors", "omit", "noCookie", "noCookie");
|
||||
await doTest(CROSS_ORIGIN, "no-cors", "omit", "noCookie", "noCookie");
|
||||
await doTest(CROSS_ORIGIN, "cors", "omit", "noCookie", "noCookie");
|
||||
});
|
@ -0,0 +1,134 @@
|
||||
const TOP_LEVEL_URL =
|
||||
getRootDirectory(gTestPath).replace(
|
||||
"chrome://mochitests/content",
|
||||
"https://example.com"
|
||||
) + "open_credentialless_document.sjs";
|
||||
|
||||
const SAME_ORIGIN = "https://example.com";
|
||||
const CROSS_ORIGIN = "https://test1.example.com";
|
||||
|
||||
const USE_CREDENTIALLESS = true;
|
||||
const NO_CREDENTIALLESS = false;
|
||||
|
||||
const GET_STATE_URL =
|
||||
getRootDirectory(gTestPath).replace(
|
||||
"chrome://mochitests/content",
|
||||
"https://example.com"
|
||||
) + "store_header.sjs?getstate";
|
||||
|
||||
async function addCookieToOrigin(origin) {
|
||||
const fetchRequestURL =
|
||||
getRootDirectory(gTestPath).replace("chrome://mochitests/content", origin) +
|
||||
"store_header.sjs?addcookie";
|
||||
|
||||
const addcookieTab = await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
fetchRequestURL
|
||||
);
|
||||
|
||||
await SpecialPowers.spawn(addcookieTab.linkedBrowser, [], async function() {
|
||||
content.document.cookie = "coep=credentialless; SameSite=None; Secure";
|
||||
});
|
||||
await BrowserTestUtils.removeTab(addcookieTab);
|
||||
}
|
||||
|
||||
async function testOrigin(
|
||||
fetchOrigin,
|
||||
isCredentialless,
|
||||
fetchRequestMode,
|
||||
fetchRequestCrendentials,
|
||||
expectedCookieResult
|
||||
) {
|
||||
let topLevelUrl = TOP_LEVEL_URL;
|
||||
if (isCredentialless) {
|
||||
topLevelUrl += "?credentialless";
|
||||
}
|
||||
|
||||
const noCredentiallessTab = await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
topLevelUrl
|
||||
);
|
||||
|
||||
const fetchRequestURL =
|
||||
getRootDirectory(gTestPath).replace(
|
||||
"chrome://mochitests/content",
|
||||
fetchOrigin
|
||||
) + "store_header.sjs?checkheader";
|
||||
|
||||
await SpecialPowers.spawn(
|
||||
noCredentiallessTab.linkedBrowser,
|
||||
[
|
||||
fetchRequestURL,
|
||||
fetchRequestMode,
|
||||
fetchRequestCrendentials,
|
||||
GET_STATE_URL,
|
||||
expectedCookieResult,
|
||||
],
|
||||
async function(
|
||||
fetchRequestURL,
|
||||
fetchRequestMode,
|
||||
fetchRequestCrendentials,
|
||||
getStateURL,
|
||||
expectedCookieResult
|
||||
) {
|
||||
// When store_header.sjs receives this request, it will store
|
||||
// whether it has received the cookie as a shared state.
|
||||
await content.fetch(fetchRequestURL, {
|
||||
mode: fetchRequestMode,
|
||||
credentials: fetchRequestCrendentials,
|
||||
});
|
||||
|
||||
// This request is used to get the saved state from the
|
||||
// previous fetch request.
|
||||
const response = await content.fetch(getStateURL, {
|
||||
mode: "cors",
|
||||
});
|
||||
const text = await response.text();
|
||||
is(text, expectedCookieResult);
|
||||
}
|
||||
);
|
||||
|
||||
await BrowserTestUtils.removeTab(noCredentiallessTab);
|
||||
}
|
||||
|
||||
async function doTest(
|
||||
origin,
|
||||
fetchRequestMode,
|
||||
fetchRequestCrendentials,
|
||||
expectedCookieResultForNoCredentialless,
|
||||
expectedCookieResultForCredentialless
|
||||
) {
|
||||
await testOrigin(
|
||||
origin,
|
||||
USE_CREDENTIALLESS,
|
||||
fetchRequestMode,
|
||||
fetchRequestCrendentials,
|
||||
expectedCookieResultForCredentialless
|
||||
);
|
||||
await testOrigin(
|
||||
origin,
|
||||
NO_CREDENTIALLESS,
|
||||
fetchRequestMode,
|
||||
fetchRequestCrendentials,
|
||||
expectedCookieResultForNoCredentialless
|
||||
);
|
||||
}
|
||||
|
||||
add_task(async function() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["browser.tabs.remote.coep.credentialless", false],
|
||||
["dom.origin-trials.enabled", true],
|
||||
["dom.origin-trials.test-key.enabled", true],
|
||||
],
|
||||
});
|
||||
|
||||
await addCookieToOrigin(SAME_ORIGIN);
|
||||
await addCookieToOrigin(CROSS_ORIGIN);
|
||||
|
||||
// Same-origin request contains Cookies.
|
||||
await doTest(SAME_ORIGIN, "no-cors", "include", "hasCookie", "hasCookie");
|
||||
await doTest(SAME_ORIGIN, "cors", "include", "hasCookie", "hasCookie");
|
||||
await doTest(SAME_ORIGIN, "no-cors", "same-origin", "hasCookie", "hasCookie");
|
||||
await doTest(SAME_ORIGIN, "cors", "same-origin", "hasCookie", "hasCookie");
|
||||
});
|
@ -0,0 +1,139 @@
|
||||
const TOP_LEVEL_URL =
|
||||
getRootDirectory(gTestPath).replace(
|
||||
"chrome://mochitests/content",
|
||||
"https://example.com"
|
||||
) + "open_credentialless_document.sjs";
|
||||
|
||||
const SAME_ORIGIN = "https://example.com";
|
||||
const CROSS_ORIGIN = "https://test1.example.com";
|
||||
|
||||
const USE_CREDENTIALLESS = true;
|
||||
const NO_CREDENTIALLESS = false;
|
||||
|
||||
const GET_STATE_URL =
|
||||
getRootDirectory(gTestPath).replace(
|
||||
"chrome://mochitests/content",
|
||||
"https://example.com"
|
||||
) + "store_header.sjs?getstate";
|
||||
|
||||
async function addCookieToOrigin(origin) {
|
||||
const fetchRequestURL =
|
||||
getRootDirectory(gTestPath).replace("chrome://mochitests/content", origin) +
|
||||
"store_header.sjs?addcookie";
|
||||
|
||||
const addcookieTab = await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
fetchRequestURL
|
||||
);
|
||||
|
||||
await SpecialPowers.spawn(addcookieTab.linkedBrowser, [], async function() {
|
||||
content.document.cookie = "coep=credentialless; SameSite=None; Secure";
|
||||
});
|
||||
await BrowserTestUtils.removeTab(addcookieTab);
|
||||
}
|
||||
|
||||
async function testOrigin(
|
||||
fetchOrigin,
|
||||
isCredentialless,
|
||||
fetchRequestMode,
|
||||
fetchRequestCrendentials,
|
||||
expectedCookieResult
|
||||
) {
|
||||
let topLevelUrl = TOP_LEVEL_URL;
|
||||
if (isCredentialless) {
|
||||
topLevelUrl += "?credentialless";
|
||||
}
|
||||
|
||||
const noCredentiallessTab = await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
topLevelUrl
|
||||
);
|
||||
|
||||
const fetchRequestURL =
|
||||
getRootDirectory(gTestPath).replace(
|
||||
"chrome://mochitests/content",
|
||||
fetchOrigin
|
||||
) + "store_header.sjs?checkheader";
|
||||
|
||||
await SpecialPowers.spawn(
|
||||
noCredentiallessTab.linkedBrowser,
|
||||
[
|
||||
fetchRequestURL,
|
||||
fetchRequestMode,
|
||||
fetchRequestCrendentials,
|
||||
GET_STATE_URL,
|
||||
expectedCookieResult,
|
||||
],
|
||||
async function(
|
||||
fetchRequestURL,
|
||||
fetchRequestMode,
|
||||
fetchRequestCrendentials,
|
||||
getStateURL,
|
||||
expectedCookieResult
|
||||
) {
|
||||
// When store_header.sjs receives this request, it will store
|
||||
// whether it has received the cookie as a shared state.
|
||||
await content.fetch(fetchRequestURL, {
|
||||
mode: fetchRequestMode,
|
||||
credentials: fetchRequestCrendentials,
|
||||
});
|
||||
|
||||
// This request is used to get the saved state from the
|
||||
// previous fetch request.
|
||||
const response = await content.fetch(getStateURL, {
|
||||
mode: "cors",
|
||||
});
|
||||
const text = await response.text();
|
||||
is(text, expectedCookieResult);
|
||||
}
|
||||
);
|
||||
|
||||
await BrowserTestUtils.removeTab(noCredentiallessTab);
|
||||
}
|
||||
|
||||
async function doTest(
|
||||
origin,
|
||||
fetchRequestMode,
|
||||
fetchRequestCrendentials,
|
||||
expectedCookieResultForNoCredentialless,
|
||||
expectedCookieResultForCredentialless
|
||||
) {
|
||||
await testOrigin(
|
||||
origin,
|
||||
USE_CREDENTIALLESS,
|
||||
fetchRequestMode,
|
||||
fetchRequestCrendentials,
|
||||
expectedCookieResultForCredentialless
|
||||
);
|
||||
await testOrigin(
|
||||
origin,
|
||||
NO_CREDENTIALLESS,
|
||||
fetchRequestMode,
|
||||
fetchRequestCrendentials,
|
||||
expectedCookieResultForNoCredentialless
|
||||
);
|
||||
}
|
||||
|
||||
add_task(async function() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["browser.tabs.remote.coep.credentialless", false],
|
||||
["dom.origin-trials.enabled", true],
|
||||
["dom.origin-trials.test-key.enabled", true],
|
||||
],
|
||||
});
|
||||
|
||||
await addCookieToOrigin(SAME_ORIGIN);
|
||||
await addCookieToOrigin(CROSS_ORIGIN);
|
||||
|
||||
// Cross-origin CORS requests contains Cookies, if credentials mode is set to
|
||||
// 'include'. This does not depends on COEP.
|
||||
await doTest(CROSS_ORIGIN, "cors", "include", "hasCookie", "hasCookie");
|
||||
await doTest(CROSS_ORIGIN, "cors", "same-origin", "noCookie", "noCookie");
|
||||
|
||||
// Cross-origin no-CORS requests includes Cookies when:
|
||||
// 1. credentials mode is 'include'
|
||||
// 2. COEP: is not credentialless.
|
||||
await doTest(CROSS_ORIGIN, "no-cors", "include", "hasCookie", "noCookie");
|
||||
await doTest(CROSS_ORIGIN, "no-cors", "same-origin", "noCookie", "noCookie");
|
||||
});
|
@ -0,0 +1,164 @@
|
||||
const TOP_LEVEL_URL =
|
||||
getRootDirectory(gTestPath).replace(
|
||||
"chrome://mochitests/content",
|
||||
"https://example.com"
|
||||
) + "open_credentialless_document.sjs";
|
||||
|
||||
const WORKER_URL =
|
||||
getRootDirectory(gTestPath).replace(
|
||||
"chrome://mochitests/content",
|
||||
"https://example.com"
|
||||
) + "credentialless_worker.sjs";
|
||||
|
||||
const GET_STATE_URL =
|
||||
getRootDirectory(gTestPath).replace(
|
||||
"chrome://mochitests/content",
|
||||
"https://example.com"
|
||||
) + "store_header.sjs?getstate";
|
||||
|
||||
const SAME_ORIGIN = "https://example.com";
|
||||
const CROSS_ORIGIN = "https://test1.example.com";
|
||||
|
||||
const WORKER_USES_CREDENTIALLESS = "credentialless";
|
||||
const WORKER_NOT_USE_CREDENTIALLESS = "";
|
||||
|
||||
async function addCookieToOrigin(origin) {
|
||||
const fetchRequestURL =
|
||||
getRootDirectory(gTestPath).replace("chrome://mochitests/content", origin) +
|
||||
"store_header.sjs?addcookie";
|
||||
|
||||
const addcookieTab = await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
fetchRequestURL
|
||||
);
|
||||
|
||||
await SpecialPowers.spawn(addcookieTab.linkedBrowser, [], async function() {
|
||||
content.document.cookie = "coep=credentialless; SameSite=None; Secure";
|
||||
});
|
||||
await BrowserTestUtils.removeTab(addcookieTab);
|
||||
}
|
||||
|
||||
async function testOrigin(
|
||||
fetchOrigin,
|
||||
isCredentialless,
|
||||
workerUsesCredentialless,
|
||||
expectedCookieResult
|
||||
) {
|
||||
let topLevelUrl = TOP_LEVEL_URL;
|
||||
if (isCredentialless) {
|
||||
topLevelUrl += "?credentialless";
|
||||
}
|
||||
const noCredentiallessTab = await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
topLevelUrl
|
||||
);
|
||||
|
||||
const fetchRequestURL =
|
||||
getRootDirectory(gTestPath).replace(
|
||||
"chrome://mochitests/content",
|
||||
fetchOrigin
|
||||
) + "store_header.sjs?checkheader";
|
||||
|
||||
let workerScriptURL = WORKER_URL + "?" + workerUsesCredentialless;
|
||||
|
||||
await SpecialPowers.spawn(
|
||||
noCredentiallessTab.linkedBrowser,
|
||||
[fetchRequestURL, GET_STATE_URL, workerScriptURL, expectedCookieResult],
|
||||
async function(
|
||||
fetchRequestURL,
|
||||
getStateURL,
|
||||
workerScriptURL,
|
||||
expectedCookieResult
|
||||
) {
|
||||
const worker = new content.Worker(workerScriptURL, {});
|
||||
|
||||
// When the worker receives this message, it'll send
|
||||
// a fetch request to fetchRequestURL, and fetchRequestURL
|
||||
// will store whether it has received the cookie as a
|
||||
// shared state.
|
||||
worker.postMessage(fetchRequestURL);
|
||||
|
||||
if (expectedCookieResult == "error") {
|
||||
await new Promise(r => {
|
||||
worker.onerror = function() {
|
||||
ok(true, "worker has error");
|
||||
r();
|
||||
};
|
||||
});
|
||||
} else {
|
||||
await new Promise(r => {
|
||||
worker.addEventListener("message", async function() {
|
||||
// This request is used to get the saved state from the
|
||||
// previous fetch request.
|
||||
const response = await content.fetch(getStateURL, {
|
||||
mode: "cors",
|
||||
});
|
||||
const text = await response.text();
|
||||
is(text, expectedCookieResult);
|
||||
r();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
await BrowserTestUtils.removeTab(noCredentiallessTab);
|
||||
}
|
||||
|
||||
async function dedicatedWorkerTest(
|
||||
origin,
|
||||
workerCOEP,
|
||||
expectedCookieResultForNoCredentialless,
|
||||
expectedCookieResultForCredentialless
|
||||
) {
|
||||
await testOrigin(
|
||||
origin,
|
||||
false,
|
||||
workerCOEP,
|
||||
expectedCookieResultForNoCredentialless
|
||||
);
|
||||
await testOrigin(
|
||||
origin,
|
||||
true,
|
||||
workerCOEP,
|
||||
expectedCookieResultForCredentialless
|
||||
);
|
||||
}
|
||||
|
||||
add_task(async function() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["browser.tabs.remote.coep.credentialless", false], // Explicitly set credentialless to false because we want to test origin trial
|
||||
["dom.origin-trials.enabled", true],
|
||||
["dom.origin-trials.test-key.enabled", true],
|
||||
],
|
||||
});
|
||||
|
||||
await addCookieToOrigin(SAME_ORIGIN);
|
||||
await addCookieToOrigin(CROSS_ORIGIN);
|
||||
|
||||
await dedicatedWorkerTest(
|
||||
SAME_ORIGIN,
|
||||
WORKER_NOT_USE_CREDENTIALLESS,
|
||||
"hasCookie",
|
||||
"error"
|
||||
);
|
||||
await dedicatedWorkerTest(
|
||||
SAME_ORIGIN,
|
||||
WORKER_USES_CREDENTIALLESS,
|
||||
"hasCookie",
|
||||
"hasCookie"
|
||||
);
|
||||
|
||||
await dedicatedWorkerTest(
|
||||
CROSS_ORIGIN,
|
||||
WORKER_NOT_USE_CREDENTIALLESS,
|
||||
"hasCookie",
|
||||
"error"
|
||||
);
|
||||
await dedicatedWorkerTest(
|
||||
CROSS_ORIGIN,
|
||||
WORKER_USES_CREDENTIALLESS,
|
||||
"noCookie",
|
||||
"noCookie"
|
||||
);
|
||||
});
|
21
dom/fetch/tests/credentialless_resource.sjs
Normal file
21
dom/fetch/tests/credentialless_resource.sjs
Normal file
@ -0,0 +1,21 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
// small red image
|
||||
const IMG_BYTES = atob(
|
||||
"iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" +
|
||||
"P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
|
||||
);
|
||||
|
||||
function handleRequest(request, response) {
|
||||
response.seizePower();
|
||||
response.write("HTTP/1.1 200 OK\r\n");
|
||||
response.write("Content-Type: image/png\r\n");
|
||||
if (request.queryString === "corp_cross_origin") {
|
||||
response.write("Cross-Origin-Resource-Policy: cross-origin\r\n");
|
||||
}
|
||||
response.write("\r\n");
|
||||
response.write(IMG_BYTES);
|
||||
response.finish();
|
||||
}
|
25
dom/fetch/tests/credentialless_worker.sjs
Normal file
25
dom/fetch/tests/credentialless_worker.sjs
Normal file
@ -0,0 +1,25 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const WORKER = `
|
||||
onmessage = function(event) {
|
||||
fetch(event.data, {
|
||||
mode: "no-cors",
|
||||
credentials: "include"
|
||||
}).then(function() {
|
||||
postMessage("fetch done");
|
||||
});
|
||||
}
|
||||
`;
|
||||
|
||||
function handleRequest(request, response) {
|
||||
if (request.queryString === "credentialless") {
|
||||
response.setHeader("Cross-Origin-Embedder-Policy", "credentialless", true);
|
||||
}
|
||||
|
||||
response.setHeader("Content-Type", "application/javascript", false);
|
||||
response.setStatusLine(request.httpVersion, "200", "Found");
|
||||
response.write(WORKER);
|
||||
}
|
23
dom/fetch/tests/open_credentialless_document.sjs
Normal file
23
dom/fetch/tests/open_credentialless_document.sjs
Normal file
@ -0,0 +1,23 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
const HTML = `<!DOCTYPE HTML>
|
||||
<head>
|
||||
<!-- Created with: mktoken --origin 'https://example.com' --feature CoepCredentialless --expiry 'Wed, 01 Jan 3000 01:00:00 +0100' --sign test-keys/test-ecdsa.pkcs8 -->
|
||||
<meta http-equiv="origin-trial" content="Az+DK2Kczk8Xz1cAlD+TkvPZmuM2uJZ2CFefbp2hLuCU9FbUqxWTyQ2tEYr50r0syKELcOZLAPaABw8aYTLHn5YAAABUeyJvcmlnaW4iOiJodHRwczovL2V4YW1wbGUuY29tIiwiZmVhdHVyZSI6IkNvZXBDcmVkZW50aWFsbGVzcyIsImV4cGlyeSI6MzI1MDM2ODAwMDB9">
|
||||
</head>
|
||||
<html>
|
||||
<body>Hello World</body>
|
||||
</html>`;
|
||||
|
||||
function handleRequest(request, response) {
|
||||
if (request.queryString == "credentialless") {
|
||||
response.setHeader("Cross-Origin-Embedder-Policy", "credentialless");
|
||||
} else if (request.queryString === "requirecorp") {
|
||||
response.setHeader("Cross-Origin-Embedder-Policy", "require-corp");
|
||||
}
|
||||
response.setHeader("Content-Type", "text/html;charset=utf-8", false);
|
||||
response.setStatusLine(request.httpVersion, "200", "Found");
|
||||
response.write(HTML);
|
||||
}
|
23
dom/fetch/tests/store_header.sjs
Normal file
23
dom/fetch/tests/store_header.sjs
Normal file
@ -0,0 +1,23 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const key = "store_header";
|
||||
function handleRequest(request, response) {
|
||||
response.setHeader("Content-Type", "text/plain");
|
||||
response.setHeader("Access-Control-Allow-Origin", "https://example.com");
|
||||
response.setHeader("Access-Control-Allow-Credentials", "true");
|
||||
|
||||
if (request.queryString === "getstate") {
|
||||
response.write(getSharedState(key));
|
||||
} else if (request.queryString === "checkheader") {
|
||||
if (request.hasHeader("Cookie")) {
|
||||
setSharedState(key, "hasCookie");
|
||||
} else {
|
||||
setSharedState(key, "noCookie");
|
||||
}
|
||||
} else {
|
||||
// This is the first request which sets the cookie
|
||||
}
|
||||
}
|
@ -2211,6 +2211,8 @@ interface nsIDOMWindowUtils : nsISupports {
|
||||
*/
|
||||
void resetMobileViewportManager();
|
||||
|
||||
bool isCoepCredentialless();
|
||||
|
||||
/**
|
||||
* NOTE: Currently works only on GTK+.
|
||||
*/
|
||||
|
@ -212,6 +212,8 @@ static int32_t PrefState(OriginTrial aTrial) {
|
||||
return StaticPrefs::dom_origin_trials_test_trial_state();
|
||||
case OriginTrial::OffscreenCanvas:
|
||||
return StaticPrefs::dom_origin_trials_offscreen_canvas_state();
|
||||
case OriginTrial::CoepCredentialless:
|
||||
return StaticPrefs::dom_origin_trials_coep_credentialless_state();
|
||||
case OriginTrial::MAX:
|
||||
MOZ_ASSERT_UNREACHABLE("Unknown trial!");
|
||||
break;
|
||||
@ -219,13 +221,7 @@ static int32_t PrefState(OriginTrial aTrial) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool OriginTrials::IsEnabled(JSContext* aCx, JSObject* aObject,
|
||||
OriginTrial aTrial) {
|
||||
if (nsContentUtils::ThreadsafeIsSystemCaller(aCx)) {
|
||||
return true;
|
||||
}
|
||||
LOG("OriginTrials::IsEnabled(%d)\n", int(aTrial));
|
||||
|
||||
bool OriginTrials::IsEnabled(OriginTrial aTrial) const {
|
||||
switch (PrefState(aTrial)) {
|
||||
case 1:
|
||||
return true;
|
||||
@ -235,6 +231,15 @@ bool OriginTrials::IsEnabled(JSContext* aCx, JSObject* aObject,
|
||||
break;
|
||||
}
|
||||
|
||||
return mEnabledTrials.contains(aTrial);
|
||||
}
|
||||
|
||||
bool OriginTrials::IsEnabled(JSContext* aCx, JSObject* aObject,
|
||||
OriginTrial aTrial) {
|
||||
if (nsContentUtils::ThreadsafeIsSystemCaller(aCx)) {
|
||||
return true;
|
||||
}
|
||||
LOG("OriginTrials::IsEnabled(%d)\n", int(aTrial));
|
||||
nsIGlobalObject* global = xpc::CurrentNativeGlobal(aCx);
|
||||
MOZ_ASSERT(global);
|
||||
return global && global->Trials().IsEnabled(aTrial);
|
||||
|
@ -40,9 +40,7 @@ class OriginTrials final {
|
||||
void UpdateFromToken(const nsAString& aBase64EncodedToken,
|
||||
nsIPrincipal* aPrincipal);
|
||||
|
||||
bool IsEnabled(OriginTrial aTrial) const {
|
||||
return mEnabledTrials.contains(aTrial);
|
||||
}
|
||||
bool IsEnabled(OriginTrial aTrial) const;
|
||||
|
||||
// Checks whether a given origin trial is enabled for a given call.
|
||||
static bool IsEnabled(JSContext*, JSObject*, OriginTrial);
|
||||
|
@ -10,6 +10,7 @@ pub enum OriginTrial {
|
||||
// NOTE(emilio): 0 is reserved for WebIDL usage.
|
||||
TestTrial = 1,
|
||||
OffscreenCanvas = 2,
|
||||
CoepCredentialless = 3,
|
||||
|
||||
MAX,
|
||||
}
|
||||
@ -19,6 +20,7 @@ impl OriginTrial {
|
||||
Some(match s {
|
||||
"TestTrial" => Self::TestTrial,
|
||||
"OffscreenCanvas" => Self::OffscreenCanvas,
|
||||
"CoepCredentialless" => Self::CoepCredentialless,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
prefs =
|
||||
dom.origin-trials.enabled=true
|
||||
dom.origin-trials.test-key.enabled=true
|
||||
browser.tabs.remote.coep.credentialless=false
|
||||
support-files =
|
||||
test_header_simple.html^headers^
|
||||
common.js
|
||||
|
@ -3,6 +3,8 @@
|
||||
<meta http-equiv="origin-trial" content="AyGdETIKWLLqe+chG57f74gZcjYSfbdYAapEq7DA49E6CmaYaPmaoXh/4tAe5XJJJdwwpFVal7hz/irC+Wvp1HgAAABLeyJvcmlnaW4iOiJodHRwczovL2V4YW1wbGUuY29tIiwiZmVhdHVyZSI6IlRlc3RUcmlhbCIsImV4cGlyeSI6MzI1MDM2ODAwMDB9">
|
||||
<!-- Created with: mktoken --origin 'https://example.com' --feature OffscreenCanvas --expiry 'Wed, 01 Jan 3000 01:00:00 +0100' --sign test-keys/test-ecdsa.pkcs8 -->
|
||||
<meta http-equiv="origin-trial" content="Ay92n3CdO5VIYbmQB7t7r7e4c34nT1k9zbX5ON2JthrXaOFxLn5NieN7ITlKhPbmPSLA4qoS+TBdshqEUwmVaIwAAABReyJvcmlnaW4iOiJodHRwczovL2V4YW1wbGUuY29tIiwiZmVhdHVyZSI6Ik9mZnNjcmVlbkNhbnZhcyIsImV4cGlyeSI6MzI1MDM2ODAwMDB9">
|
||||
<!-- Created with: mktoken --origin 'https://example.com' --feature CoepCredentialless --expiry 'Wed, 01 Jan 3000 01:00:00 +0100' --sign test-keys/test-ecdsa.pkcs8 -->
|
||||
<meta http-equiv="origin-trial" content="Az+DK2Kczk8Xz1cAlD+TkvPZmuM2uJZ2CFefbp2hLuCU9FbUqxWTyQ2tEYr50r0syKELcOZLAPaABw8aYTLHn5YAAABUeyJvcmlnaW4iOiJodHRwczovL2V4YW1wbGUuY29tIiwiZmVhdHVyZSI6IkNvZXBDcmVkZW50aWFsbGVzcyIsImV4cGlyeSI6MzI1MDM2ODAwMDB9">
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="common.js"></script>
|
||||
<script>
|
||||
@ -10,4 +12,7 @@
|
||||
add_task(function() {
|
||||
ok(!!self.OffscreenCanvas, "OffscreenCanvas trial works.");
|
||||
});
|
||||
add_task(function() {
|
||||
ok(!!SpecialPowers.DOMWindowUtils.isCoepCredentialless(), "CoepCredentialless trial works.");
|
||||
});
|
||||
</script>
|
||||
|
@ -382,7 +382,9 @@ void CacheLoadHandler::ResolvedCallback(JSContext* aCx,
|
||||
headers->Get("cross-origin-embedder-policy"_ns, coepHeader, IgnoreErrors());
|
||||
|
||||
nsILoadInfo::CrossOriginEmbedderPolicy coep =
|
||||
NS_GetCrossOriginEmbedderPolicyFromHeader(coepHeader);
|
||||
NS_GetCrossOriginEmbedderPolicyFromHeader(
|
||||
coepHeader,
|
||||
mWorkerPrivate->Trials().IsEnabled(OriginTrial::CoepCredentialless));
|
||||
|
||||
rv = ScriptResponseHeaderProcessor::ProcessCrossOriginEmbedderPolicyHeader(
|
||||
mWorkerPrivate, coep, mLoader->IsMainScript());
|
||||
|
@ -49,7 +49,9 @@ nsresult ScriptResponseHeaderProcessor::ProcessCrossOriginEmbedderPolicyHeader(
|
||||
}
|
||||
|
||||
nsILoadInfo::CrossOriginEmbedderPolicy coep;
|
||||
MOZ_TRY(httpChannel->GetResponseEmbedderPolicy(&coep));
|
||||
MOZ_TRY(httpChannel->GetResponseEmbedderPolicy(
|
||||
mWorkerPrivate->Trials().IsEnabled(OriginTrial::CoepCredentialless),
|
||||
&coep));
|
||||
|
||||
return ProcessCrossOriginEmbedderPolicyHeader(mWorkerPrivate, coep,
|
||||
mIsMainScript);
|
||||
|
@ -537,7 +537,9 @@ nsresult LoadInfoToLoadInfoArgs(nsILoadInfo* aLoadInfo,
|
||||
aLoadInfo->GetIsFromObjectOrEmbed(), cookieJarSettingsArgs,
|
||||
aLoadInfo->GetRequestBlockingReason(), maybeCspToInheritInfo,
|
||||
aLoadInfo->GetStoragePermission(), aLoadInfo->GetIsMetaRefresh(),
|
||||
aLoadInfo->GetLoadingEmbedderPolicy(), unstrippedURI));
|
||||
aLoadInfo->GetLoadingEmbedderPolicy(),
|
||||
aLoadInfo->GetIsOriginTrialCoepCredentiallessEnabledForTopLevel(),
|
||||
unstrippedURI));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -779,7 +781,9 @@ nsresult LoadInfoArgsToLoadInfo(
|
||||
loadInfoArgs.isInDevToolsContext(), loadInfoArgs.parserCreatedScript(),
|
||||
loadInfoArgs.storagePermission(), loadInfoArgs.isMetaRefresh(),
|
||||
loadInfoArgs.requestBlockingReason(), loadingContext,
|
||||
loadInfoArgs.loadingEmbedderPolicy(), loadInfoArgs.unstrippedURI());
|
||||
loadInfoArgs.loadingEmbedderPolicy(),
|
||||
loadInfoArgs.originTrialCoepCredentiallessEnabledForTopLevel(),
|
||||
loadInfoArgs.unstrippedURI());
|
||||
|
||||
if (loadInfoArgs.isFromProcessingFrameAttributes()) {
|
||||
loadInfo->SetIsFromProcessingFrameAttributes();
|
||||
|
@ -1542,6 +1542,7 @@
|
||||
type: RelaxedAtomicBool
|
||||
value: @IS_NIGHTLY_BUILD@
|
||||
mirror: always
|
||||
do_not_use_directly: true
|
||||
|
||||
# When this pref is enabled top level loads with a mismatched
|
||||
# Cross-Origin-Opener-Policy header will be loaded in a separate process.
|
||||
@ -2997,6 +2998,13 @@
|
||||
value: 0
|
||||
mirror: always
|
||||
|
||||
# Origin trial state for COEP: Credentialless.
|
||||
# 0: normal, 1: always-enabled, 2: always-disabled
|
||||
- name: dom.origin-trials.coep-credentialless.state
|
||||
type: RelaxedAtomicInt32
|
||||
value: 0
|
||||
mirror: always
|
||||
|
||||
# Is support for Window.paintWorklet enabled?
|
||||
- name: dom.paintWorklet.enabled
|
||||
type: bool
|
||||
|
@ -513,6 +513,11 @@ LoadInfo::LoadInfo(dom::WindowGlobalParent* aParentWGP,
|
||||
RefPtr<WindowContext> ctx = WindowContext::GetById(mInnerWindowID);
|
||||
if (ctx) {
|
||||
mLoadingEmbedderPolicy = ctx->GetEmbedderPolicy();
|
||||
|
||||
if (Document* document = ctx->GetDocument()) {
|
||||
mIsOriginTrialCoepCredentiallessEnabledForTopLevel =
|
||||
document->Trials().IsEnabled(OriginTrial::CoepCredentialless);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -601,6 +606,8 @@ LoadInfo::LoadInfo(const LoadInfo& rhs)
|
||||
mIsMediaInitialRequest(rhs.mIsMediaInitialRequest),
|
||||
mIsFromObjectOrEmbed(rhs.mIsFromObjectOrEmbed),
|
||||
mLoadingEmbedderPolicy(rhs.mLoadingEmbedderPolicy),
|
||||
mIsOriginTrialCoepCredentiallessEnabledForTopLevel(
|
||||
rhs.mIsOriginTrialCoepCredentiallessEnabledForTopLevel),
|
||||
mUnstrippedURI(rhs.mUnstrippedURI) {}
|
||||
|
||||
LoadInfo::LoadInfo(
|
||||
@ -640,6 +647,7 @@ LoadInfo::LoadInfo(
|
||||
nsILoadInfo::StoragePermissionState aStoragePermission, bool aIsMetaRefresh,
|
||||
uint32_t aRequestBlockingReason, nsINode* aLoadingContext,
|
||||
nsILoadInfo::CrossOriginEmbedderPolicy aLoadingEmbedderPolicy,
|
||||
bool aIsOriginTrialCoepCredentiallessEnabledForTopLevel,
|
||||
nsIURI* aUnstrippedURI)
|
||||
: mLoadingPrincipal(aLoadingPrincipal),
|
||||
mTriggeringPrincipal(aTriggeringPrincipal),
|
||||
@ -707,6 +715,8 @@ LoadInfo::LoadInfo(
|
||||
mIsMetaRefresh(aIsMetaRefresh),
|
||||
|
||||
mLoadingEmbedderPolicy(aLoadingEmbedderPolicy),
|
||||
mIsOriginTrialCoepCredentiallessEnabledForTopLevel(
|
||||
aIsOriginTrialCoepCredentiallessEnabledForTopLevel),
|
||||
mUnstrippedURI(aUnstrippedURI) {
|
||||
// Only top level TYPE_DOCUMENT loads can have a null loadingPrincipal
|
||||
MOZ_ASSERT(mLoadingPrincipal ||
|
||||
@ -2104,6 +2114,22 @@ LoadInfo::SetLoadingEmbedderPolicy(
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetIsOriginTrialCoepCredentiallessEnabledForTopLevel(
|
||||
bool* aIsOriginTrialCoepCredentiallessEnabledForTopLevel) {
|
||||
*aIsOriginTrialCoepCredentiallessEnabledForTopLevel =
|
||||
mIsOriginTrialCoepCredentiallessEnabledForTopLevel;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::SetIsOriginTrialCoepCredentiallessEnabledForTopLevel(
|
||||
bool aIsOriginTrialCoepCredentiallessEnabledForTopLevel) {
|
||||
mIsOriginTrialCoepCredentiallessEnabledForTopLevel =
|
||||
aIsOriginTrialCoepCredentiallessEnabledForTopLevel;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIContentSecurityPolicy> LoadInfo::GetCsp() {
|
||||
// Before querying the CSP from the client we have to check if the
|
||||
// triggeringPrincipal originates from an addon and potentially
|
||||
|
@ -232,6 +232,7 @@ class LoadInfo final : public nsILoadInfo {
|
||||
bool aIsMetaRefresh, uint32_t aRequestBlockingReason,
|
||||
nsINode* aLoadingContext,
|
||||
nsILoadInfo::CrossOriginEmbedderPolicy aLoadingEmbedderPolicy,
|
||||
bool aIsOriginTrialCoepCredentiallessEnabledForTopLevel,
|
||||
nsIURI* aUnstrippedURI);
|
||||
LoadInfo(const LoadInfo& rhs);
|
||||
|
||||
@ -359,6 +360,8 @@ class LoadInfo final : public nsILoadInfo {
|
||||
nsILoadInfo::CrossOriginEmbedderPolicy mLoadingEmbedderPolicy =
|
||||
nsILoadInfo::EMBEDDER_POLICY_NULL;
|
||||
|
||||
bool mIsOriginTrialCoepCredentiallessEnabledForTopLevel = false;
|
||||
|
||||
nsCOMPtr<nsIURI> mUnstrippedURI;
|
||||
};
|
||||
|
||||
|
@ -746,6 +746,18 @@ TRRLoadInfo::SetLoadingEmbedderPolicy(
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TRRLoadInfo::GetIsOriginTrialCoepCredentiallessEnabledForTopLevel(
|
||||
bool* aIsOriginTrialCoepCredentiallessEnabledForTopLevel) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TRRLoadInfo::SetIsOriginTrialCoepCredentiallessEnabledForTopLevel(
|
||||
bool aIsOriginTrialCoepCredentiallessEnabledForTopLevel) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TRRLoadInfo::GetUnstrippedURI(nsIURI** aURI) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
|
@ -1394,6 +1394,11 @@ interface nsILoadInfo : nsISupports
|
||||
[infallible] attribute nsILoadInfo_CrossOriginEmbedderPolicy
|
||||
loadingEmbedderPolicy;
|
||||
|
||||
/**
|
||||
* This attribute will be true if the top level document has COEP:
|
||||
* credentialless enabled in Origin Trial.
|
||||
*/
|
||||
[infallible] attribute boolean isOriginTrialCoepCredentiallessEnabledForTopLevel;
|
||||
/**
|
||||
* This attribute will be true if this is a load triggered by a media
|
||||
* element.
|
||||
|
@ -2605,7 +2605,8 @@ nsresult NS_MaybeOpenChannelUsingAsyncOpen(nsIChannel* aChannel,
|
||||
}
|
||||
|
||||
nsILoadInfo::CrossOriginEmbedderPolicy
|
||||
NS_GetCrossOriginEmbedderPolicyFromHeader(const nsACString& aHeader) {
|
||||
NS_GetCrossOriginEmbedderPolicyFromHeader(
|
||||
const nsACString& aHeader, bool aIsOriginTrialCoepCredentiallessEnabled) {
|
||||
nsCOMPtr<nsISFVService> sfv = GetSFVService();
|
||||
|
||||
nsCOMPtr<nsISFVItem> item;
|
||||
@ -2634,7 +2635,8 @@ NS_GetCrossOriginEmbedderPolicyFromHeader(const nsACString& aHeader) {
|
||||
if (embedderPolicy.EqualsLiteral("require-corp")) {
|
||||
return nsILoadInfo::EMBEDDER_POLICY_REQUIRE_CORP;
|
||||
} else if (embedderPolicy.EqualsLiteral("credentialless") &&
|
||||
StaticPrefs::browser_tabs_remote_coep_credentialless()) {
|
||||
IsCoepCredentiallessEnabled(
|
||||
aIsOriginTrialCoepCredentiallessEnabled)) {
|
||||
return nsILoadInfo::EMBEDDER_POLICY_CREDENTIALLESS;
|
||||
}
|
||||
|
||||
@ -3901,3 +3903,9 @@ void CheckForBrokenChromeURL(nsILoadInfo* aLoadInfo, nsIURI* aURI) {
|
||||
printf_stderr("Missing chrome or resource URL: %s\n", spec.get());
|
||||
}
|
||||
}
|
||||
|
||||
bool IsCoepCredentiallessEnabled(bool aIsOriginTrialCoepCredentiallessEnabled) {
|
||||
return StaticPrefs::
|
||||
browser_tabs_remote_coep_credentialless_DoNotUseDirectly() ||
|
||||
aIsOriginTrialCoepCredentiallessEnabled;
|
||||
}
|
||||
|
@ -59,6 +59,7 @@ class nsIIncrementalStreamLoaderObserver;
|
||||
namespace mozilla {
|
||||
class Encoding;
|
||||
class OriginAttributes;
|
||||
class OriginTrials;
|
||||
namespace dom {
|
||||
class ClientInfo;
|
||||
class PerformanceStorage;
|
||||
@ -831,7 +832,8 @@ nsresult NS_MaybeOpenChannelUsingAsyncOpen(nsIChannel* aChannel,
|
||||
* See: https://mikewest.github.io/corpp/#parsing
|
||||
*/
|
||||
nsILoadInfo::CrossOriginEmbedderPolicy
|
||||
NS_GetCrossOriginEmbedderPolicyFromHeader(const nsACString& aHeader);
|
||||
NS_GetCrossOriginEmbedderPolicyFromHeader(
|
||||
const nsACString& aHeader, bool aIsOriginTrialCoepCredentiallessEnabled);
|
||||
|
||||
/** Given the first (disposition) token from a Content-Disposition header,
|
||||
* tell whether it indicates the content is inline or attachment
|
||||
@ -1069,4 +1071,6 @@ nsresult NS_HasRootDomain(const nsACString& aInput, const nsACString& aHost,
|
||||
|
||||
void CheckForBrokenChromeURL(nsILoadInfo* aLoadInfo, nsIURI* aURI);
|
||||
|
||||
bool IsCoepCredentiallessEnabled(bool aIsOriginTrialCoepCredentiallessEnabled);
|
||||
|
||||
#endif // !nsNetUtil_h__
|
||||
|
@ -166,6 +166,7 @@ struct LoadInfoArgs
|
||||
StoragePermissionState storagePermission;
|
||||
bool isMetaRefresh;
|
||||
CrossOriginEmbedderPolicy loadingEmbedderPolicy;
|
||||
bool originTrialCoepCredentiallessEnabledForTopLevel;
|
||||
nsIURI unstrippedURI;
|
||||
};
|
||||
|
||||
|
@ -772,6 +772,7 @@ NS_IMETHODIMP ClassifierDummyChannel::IsThirdPartySocialTrackingResource(
|
||||
void ClassifierDummyChannel::DoDiagnosticAssertWhenOnStopNotCalledOnDestroy() {}
|
||||
|
||||
NS_IMETHODIMP ClassifierDummyChannel::GetResponseEmbedderPolicy(
|
||||
bool aIsOriginTrialCoepCredentiallessEnabled,
|
||||
nsILoadInfo::CrossOriginEmbedderPolicy* aOutPolicy) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "ReferrerInfo.h"
|
||||
#include "mozIRemoteLazyInputStream.h"
|
||||
#include "mozIThirdPartyUtil.h"
|
||||
#include "mozilla/LoadInfo.h"
|
||||
#include "mozilla/AntiTrackingUtils.h"
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
#include "mozilla/BinarySearch.h"
|
||||
@ -2403,7 +2404,11 @@ nsresult HttpBaseChannel::ProcessCrossOriginEmbedderPolicyHeader() {
|
||||
|
||||
nsILoadInfo::CrossOriginEmbedderPolicy resultPolicy =
|
||||
nsILoadInfo::EMBEDDER_POLICY_NULL;
|
||||
rv = GetResponseEmbedderPolicy(&resultPolicy);
|
||||
bool isCoepCredentiallessEnabled;
|
||||
rv = mLoadInfo->GetIsOriginTrialCoepCredentiallessEnabledForTopLevel(
|
||||
&isCoepCredentiallessEnabled);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = GetResponseEmbedderPolicy(isCoepCredentiallessEnabled, &resultPolicy);
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_OK;
|
||||
}
|
||||
@ -2469,8 +2474,7 @@ nsresult HttpBaseChannel::ProcessCrossOriginResourcePolicyHeader() {
|
||||
if (StaticPrefs::browser_tabs_remote_useCrossOriginEmbedderPolicy()) {
|
||||
if (content.IsEmpty()) {
|
||||
if (mLoadInfo->GetLoadingEmbedderPolicy() ==
|
||||
nsILoadInfo::EMBEDDER_POLICY_CREDENTIALLESS &&
|
||||
StaticPrefs::browser_tabs_remote_coep_credentialless()) {
|
||||
nsILoadInfo::EMBEDDER_POLICY_CREDENTIALLESS) {
|
||||
bool requestIncludesCredentials = false;
|
||||
nsresult rv = GetCorsIncludeCredentials(&requestIncludesCredentials);
|
||||
if (NS_FAILED(rv)) {
|
||||
@ -5670,6 +5674,7 @@ void HttpBaseChannel::SetIPv4Disabled() { mCaps |= NS_HTTP_DISABLE_IPV4; }
|
||||
void HttpBaseChannel::SetIPv6Disabled() { mCaps |= NS_HTTP_DISABLE_IPV6; }
|
||||
|
||||
NS_IMETHODIMP HttpBaseChannel::GetResponseEmbedderPolicy(
|
||||
bool aIsOriginTrialCoepCredentiallessEnabled,
|
||||
nsILoadInfo::CrossOriginEmbedderPolicy* aOutPolicy) {
|
||||
*aOutPolicy = nsILoadInfo::EMBEDDER_POLICY_NULL;
|
||||
if (!mResponseHead) {
|
||||
@ -5684,8 +5689,8 @@ NS_IMETHODIMP HttpBaseChannel::GetResponseEmbedderPolicy(
|
||||
nsAutoCString content;
|
||||
Unused << mResponseHead->GetHeader(nsHttp::Cross_Origin_Embedder_Policy,
|
||||
content);
|
||||
|
||||
*aOutPolicy = NS_GetCrossOriginEmbedderPolicyFromHeader(content);
|
||||
*aOutPolicy = NS_GetCrossOriginEmbedderPolicyFromHeader(
|
||||
content, aIsOriginTrialCoepCredentiallessEnabled);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -5747,11 +5752,15 @@ NS_IMETHODIMP HttpBaseChannel::ComputeCrossOriginOpenerPolicy(
|
||||
} else if (openerPolicy.EqualsLiteral("same-origin-allow-popups")) {
|
||||
policy = nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_ALLOW_POPUPS;
|
||||
}
|
||||
|
||||
if (policy == nsILoadInfo::OPENER_POLICY_SAME_ORIGIN) {
|
||||
nsILoadInfo::CrossOriginEmbedderPolicy coep =
|
||||
nsILoadInfo::EMBEDDER_POLICY_NULL;
|
||||
if (NS_SUCCEEDED(GetResponseEmbedderPolicy(&coep)) &&
|
||||
bool isCoepCredentiallessEnabled;
|
||||
rv = mLoadInfo->GetIsOriginTrialCoepCredentiallessEnabledForTopLevel(
|
||||
&isCoepCredentiallessEnabled);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (NS_SUCCEEDED(
|
||||
GetResponseEmbedderPolicy(isCoepCredentiallessEnabled, &coep)) &&
|
||||
(coep == nsILoadInfo::EMBEDDER_POLICY_REQUIRE_CORP ||
|
||||
coep == nsILoadInfo::EMBEDDER_POLICY_CREDENTIALLESS)) {
|
||||
policy =
|
||||
|
@ -330,6 +330,7 @@ class HttpBaseChannel : public nsHashPropertyBag,
|
||||
nsILoadInfo::CrossOriginOpenerPolicy* aOutPolicy) override;
|
||||
NS_IMETHOD HasCrossOriginOpenerPolicyMismatch(bool* aIsMismatch) override;
|
||||
NS_IMETHOD GetResponseEmbedderPolicy(
|
||||
bool aIsOriginTrialCoepCredentiallessEnabled,
|
||||
nsILoadInfo::CrossOriginEmbedderPolicy* aOutPolicy) override;
|
||||
|
||||
inline void CleanRedirectCacheChainIfNecessary() {
|
||||
|
@ -442,7 +442,7 @@ interface nsIHttpChannelInternal : nsISupports
|
||||
bool hasCrossOriginOpenerPolicyMismatch();
|
||||
|
||||
[noscript]
|
||||
nsILoadInfo_CrossOriginEmbedderPolicy getResponseEmbedderPolicy();
|
||||
nsILoadInfo_CrossOriginEmbedderPolicy getResponseEmbedderPolicy(in boolean aIsOriginTrialCoepCredentiallessEnabled);
|
||||
|
||||
[noscript, notxpcom, nostdcall]
|
||||
void DoDiagnosticAssertWhenOnStopNotCalledOnDestroy();
|
||||
|
Loading…
Reference in New Issue
Block a user