зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1725173: Add sec-fetch tests for extension content scripts. r=ckerschb,robwu
Differential Revision: https://phabricator.services.mozilla.com/D122361
This commit is contained in:
Родитель
524e95c9e4
Коммит
d9e823a6f5
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "SecFetch.h"
|
||||
#include "nsIHttpChannel.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIRedirectHistoryEntry.h"
|
||||
#include "nsIReferrerInfo.h"
|
||||
#include "mozIThirdPartyUtil.h"
|
||||
|
@ -113,6 +114,25 @@ nsCString MapInternalContentPolicyTypeToDest(nsContentPolicyType aType) {
|
|||
MOZ_CRASH("Unhandled nsContentPolicyType value");
|
||||
}
|
||||
|
||||
// Helper function to determine if a ExpandedPrincipal is of the same-origin as
|
||||
// a URI in the sec-fetch context.
|
||||
void IsExpandedPrincipalSameOrigin(
|
||||
nsCOMPtr<nsIExpandedPrincipal> aExpandedPrincipal, nsIURI* aURI,
|
||||
bool aIsPrivateWin, bool* aRes) {
|
||||
*aRes = false;
|
||||
for (const auto& principal : aExpandedPrincipal->AllowList()) {
|
||||
// Ignore extension principals to continue treating
|
||||
// "moz-extension:"-requests as not "same-origin".
|
||||
if (!mozilla::BasePrincipal::Cast(principal)->AddonPolicy()) {
|
||||
// A ExpandedPrincipal usually has at most one ContentPrincipal, so we can
|
||||
// check IsSameOrigin on it here and return early.
|
||||
mozilla::BasePrincipal::Cast(principal)->IsSameOrigin(aURI, aIsPrivateWin,
|
||||
aRes);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to determine whether a request (including involved
|
||||
// redirects) is same-origin in the context of SecFetch.
|
||||
bool IsSameOrigin(nsIHttpChannel* aHTTPChannel) {
|
||||
|
@ -131,9 +151,15 @@ bool IsSameOrigin(nsIHttpChannel* aHTTPChannel) {
|
|||
|
||||
bool isPrivateWin = loadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
|
||||
bool isSameOrigin = false;
|
||||
nsresult rv = loadInfo->TriggeringPrincipal()->IsSameOrigin(
|
||||
channelURI, isPrivateWin, &isSameOrigin);
|
||||
mozilla::Unused << NS_WARN_IF(NS_FAILED(rv));
|
||||
if (nsContentUtils::IsExpandedPrincipal(loadInfo->TriggeringPrincipal())) {
|
||||
nsCOMPtr<nsIExpandedPrincipal> ep =
|
||||
do_QueryInterface(loadInfo->TriggeringPrincipal());
|
||||
IsExpandedPrincipalSameOrigin(ep, channelURI, isPrivateWin, &isSameOrigin);
|
||||
} else {
|
||||
nsresult rv = loadInfo->TriggeringPrincipal()->IsSameOrigin(
|
||||
channelURI, isPrivateWin, &isSameOrigin);
|
||||
mozilla::Unused << NS_WARN_IF(NS_FAILED(rv));
|
||||
}
|
||||
|
||||
// if the initial request is not same-origin, we can return here
|
||||
// because we already know it's not a same-origin request
|
||||
|
@ -147,8 +173,8 @@ bool IsSameOrigin(nsIHttpChannel* aHTTPChannel) {
|
|||
for (nsIRedirectHistoryEntry* entry : loadInfo->RedirectChain()) {
|
||||
entry->GetPrincipal(getter_AddRefs(redirectPrincipal));
|
||||
if (redirectPrincipal) {
|
||||
rv = redirectPrincipal->IsSameOrigin(channelURI, isPrivateWin,
|
||||
&isSameOrigin);
|
||||
nsresult rv = redirectPrincipal->IsSameOrigin(channelURI, isPrivateWin,
|
||||
&isSameOrigin);
|
||||
mozilla::Unused << NS_WARN_IF(NS_FAILED(rv));
|
||||
if (!isSameOrigin) {
|
||||
return false;
|
||||
|
|
|
@ -5,7 +5,12 @@
|
|||
const server = createHttpServer({
|
||||
// We need the 127.0.0.1 proxy because the sec-fetch headers are not sent to
|
||||
// "127.0.0.1:<any port other than 80 or 443>".
|
||||
hosts: ["127.0.0.1"],
|
||||
hosts: ["127.0.0.1", "127.0.0.2"],
|
||||
});
|
||||
|
||||
server.registerPathHandler("/page.html", (request, response) => {
|
||||
response.setStatusLine(request.httpVersion, 200, "OK");
|
||||
response.setHeader("Access-Control-Allow-Origin", "*");
|
||||
});
|
||||
|
||||
server.registerPathHandler("/return_headers", (request, response) => {
|
||||
|
@ -26,6 +31,26 @@ server.registerPathHandler("/return_headers", (request, response) => {
|
|||
response.write(JSON.stringify(headers));
|
||||
});
|
||||
|
||||
async function contentScript() {
|
||||
const results = await Promise.all([
|
||||
// A cross-origin request from the content script.
|
||||
// Sending requests with CORS from content scripts is currently not possible
|
||||
// (Bug 1605197)
|
||||
//fetch("http://127.0.0.1/return_headers").then(res => res.json()),
|
||||
|
||||
// A cross-origin request that behaves as if it was sent by the content it
|
||||
// self.
|
||||
content.fetch("http://127.0.0.1/return_headers").then(res => res.json()),
|
||||
// A same-origin request that behaves as if it was sent by the content it
|
||||
// self.
|
||||
content.fetch("http://127.0.0.2/return_headers").then(res => res.json()),
|
||||
// A same-origin request from the content script.
|
||||
fetch("http://127.0.0.2/return_headers").then(res => res.json()),
|
||||
]);
|
||||
|
||||
browser.test.sendMessage("content_results", results);
|
||||
}
|
||||
|
||||
async function runSecFetchTest(test) {
|
||||
let data = {
|
||||
async background() {
|
||||
|
@ -40,6 +65,15 @@ async function runSecFetchTest(test) {
|
|||
},
|
||||
manifest: {
|
||||
manifest_version: 2,
|
||||
content_scripts: [
|
||||
{
|
||||
matches: ["http://127.0.0.2/*"],
|
||||
js: ["content_script.js"],
|
||||
},
|
||||
],
|
||||
},
|
||||
files: {
|
||||
"content_script.js": contentScript,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -48,7 +82,7 @@ async function runSecFetchTest(test) {
|
|||
const site = "http://127.0.0.1";
|
||||
|
||||
if (test.permission) {
|
||||
data.manifest.permissions = [`${site}/*`];
|
||||
data.manifest.permissions = ["http://127.0.0.2/*", `${site}/*`];
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension(data);
|
||||
|
@ -56,29 +90,70 @@ async function runSecFetchTest(test) {
|
|||
|
||||
extension.sendMessage(site);
|
||||
let backgroundResults = await extension.awaitMessage("background_results");
|
||||
Assert.deepEqual(backgroundResults, test.expectedHeaders);
|
||||
Assert.deepEqual(backgroundResults, test.expectedBackgroundHeaders);
|
||||
|
||||
let contentPage = await ExtensionTestUtils.loadContentPage(
|
||||
`http://127.0.0.2/page.html`
|
||||
);
|
||||
let contentResults = await extension.awaitMessage("content_results");
|
||||
Assert.deepEqual(contentResults, test.expectedContentHeaders);
|
||||
await contentPage.close();
|
||||
|
||||
await extension.unload();
|
||||
}
|
||||
|
||||
add_task(async function test_background_fetch_without_permission() {
|
||||
add_task(async function test_fetch_without_permissions() {
|
||||
await runSecFetchTest({
|
||||
permission: false,
|
||||
expectedHeaders: {
|
||||
expectedBackgroundHeaders: {
|
||||
"sec-fetch-site": "cross-site",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-dest": "empty",
|
||||
},
|
||||
expectedContentHeaders: [
|
||||
{
|
||||
"sec-fetch-site": "cross-site",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-dest": "empty",
|
||||
},
|
||||
{
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-dest": "empty",
|
||||
},
|
||||
{
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-dest": "empty",
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_background_fetch_with_permission() {
|
||||
add_task(async function test_fetch_with_permissions() {
|
||||
await runSecFetchTest({
|
||||
permission: true,
|
||||
expectedHeaders: {
|
||||
expectedBackgroundHeaders: {
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-dest": "empty",
|
||||
},
|
||||
expectedContentHeaders: [
|
||||
{
|
||||
"sec-fetch-site": "cross-site",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-dest": "empty",
|
||||
},
|
||||
{
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-dest": "empty",
|
||||
},
|
||||
{
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-dest": "empty",
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
|
Загрузка…
Ссылка в новой задаче