зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1714299 - Correct the opaque response judgment for opaque response blocking. r=necko-reviewers,annevk,dragana
An opaque response should be not only cross-origin but also be request with no_cors request mode. To filter out the request with mode Same_origin, navigate, and cors. This patch reuses the algorithm in InternalRequest/FetchDriver to decide whether a response is an opaque response. https://searchfox.org/mozilla-central/rev/da5d08750e504f3710f7ea051327d9c311c39902/dom/fetch/InternalRequest.cpp#331 https://searchfox.org/mozilla-central/rev/da5d08750e504f3710f7ea051327d9c311c39902/dom/fetch/FetchDriver.cpp#1153,1157 Differential Revision: https://phabricator.services.mozilla.com/D117086
This commit is contained in:
Родитель
d7c2b12fbe
Коммит
ef08c8d49b
|
@ -2800,32 +2800,38 @@ bool HttpBaseChannel::EnsureOpaqueResponseIsAllowed() {
|
|||
return true;
|
||||
}
|
||||
|
||||
// Check if it's cross-origin without CORS.
|
||||
const bool isPrivateWin =
|
||||
mLoadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
|
||||
bool isSameOrigin = false;
|
||||
principal->IsSameOrigin(mURI, isPrivateWin, &isSameOrigin);
|
||||
if (isSameOrigin) {
|
||||
// Check if the response is a opaque response, which means requestMode should
|
||||
// be RequestMode::No_cors and responseType should be ResponseType::Opaque.
|
||||
nsContentPolicyType contentPolicy = mLoadInfo->InternalContentPolicyType();
|
||||
// Skip the RequestMode would be RequestMode::Navigate
|
||||
if (contentPolicy == nsIContentPolicy::TYPE_DOCUMENT ||
|
||||
contentPolicy == nsIContentPolicy::TYPE_SUBDOCUMENT ||
|
||||
contentPolicy == nsIContentPolicy::TYPE_INTERNAL_FRAME ||
|
||||
contentPolicy == nsIContentPolicy::TYPE_INTERNAL_IFRAME ||
|
||||
// Skip the RequestMode would be RequestMode::Same_origin
|
||||
contentPolicy == nsIContentPolicy::TYPE_INTERNAL_WORKER ||
|
||||
contentPolicy == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsAutoCString corsOrigin;
|
||||
nsresult rv = mResponseHead->GetHeader(
|
||||
nsHttp::ResolveAtom("Access-Control-Allow-Origin"_ns), corsOrigin);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (corsOrigin.Equals("*")) {
|
||||
return true;
|
||||
}
|
||||
uint32_t securityMode = mLoadInfo->GetSecurityMode();
|
||||
// Skip when RequestMode would not be RequestMode::no_cors
|
||||
if (securityMode !=
|
||||
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT &&
|
||||
securityMode != nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> corsOriginURI;
|
||||
rv = NS_NewURI(getter_AddRefs(corsOriginURI), corsOrigin);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
bool isSameOrigin = false;
|
||||
principal->IsSameOrigin(corsOriginURI, isPrivateWin, &isSameOrigin);
|
||||
if (isSameOrigin) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Only continue when ResponseType would be ResponseType::Opaque
|
||||
if (mLoadInfo->GetTainting() != mozilla::LoadTainting::Opaque) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Exclude object/embed element
|
||||
auto extContentPolicyType = mLoadInfo->GetExternalContentPolicyType();
|
||||
if (extContentPolicyType == ExtContentPolicy::TYPE_OBJECT ||
|
||||
extContentPolicyType == ExtContentPolicy::TYPE_OBJECT_SUBREQUEST) {
|
||||
return true;
|
||||
}
|
||||
|
||||
InitiateORBTelemetry();
|
||||
|
|
|
@ -29,6 +29,8 @@ support-files =
|
|||
res_not_200or206.mp3^headers^
|
||||
res_img_for_unknown_decoder
|
||||
res_img_for_unknown_decoder^headers^
|
||||
res_object.html
|
||||
res_sub_document.html
|
||||
|
||||
[browser_about_cache.js]
|
||||
[browser_bug1535877.js]
|
||||
|
|
|
@ -29,6 +29,8 @@ const MEDIA_206_URL = `${ORIGIN2}/${DIRPATH}res_206.mp3`;
|
|||
const MEDIA_INVALID_PARTIAL_URL = `${ORIGIN2}/${DIRPATH}res_invalid_partial.mp3`;
|
||||
const MEDIA_NOT_200OR206_URL = `${ORIGIN2}/${DIRPATH}res_not_200or206.mp3`;
|
||||
const IMAGE_UNKNOWN_DECOEDER_URL = `${ORIGIN2}/${DIRPATH}res_img_for_unknown_decoder`;
|
||||
const SUBDOCUMENT_URL = `${ORIGIN2}/${DIRPATH}/res_sub_document.html`;
|
||||
const SAME_ORIGIN_OBJECT_URL = `${ORIGIN1}/${DIRPATH}/res_object.html`;
|
||||
|
||||
add_task(async function() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
|
@ -41,62 +43,100 @@ add_task(async function() {
|
|||
{
|
||||
url: SAFE_LISTED_URL,
|
||||
key: "Allowed_SafeListed",
|
||||
shouldRecorded: true,
|
||||
},
|
||||
{
|
||||
url: BLOCKED_LISTED_NEVER_SNIFFED_URL,
|
||||
key: "Blocked_BlockListedNeverSniffed",
|
||||
shouldRecorded: true,
|
||||
},
|
||||
{
|
||||
url: BLOCKED_LISTED_206_URL,
|
||||
key: "Blocked_206AndBlockListed",
|
||||
shouldRecorded: true,
|
||||
},
|
||||
{
|
||||
url: BLOCKED_LISTED_NOSNIFF_URL,
|
||||
key: "Blocked_NosniffAndEitherBlockListedOrTextPlain",
|
||||
shouldRecorded: true,
|
||||
},
|
||||
{
|
||||
url: IMAGE_URL,
|
||||
key: "Allowed_SniffAsImageOrAudioOrVideo",
|
||||
shouldRecorded: true,
|
||||
},
|
||||
{
|
||||
url: NOSNIFF_URL,
|
||||
key: "Blocked_NoSniffHeaderAfterSniff",
|
||||
shouldRecorded: true,
|
||||
},
|
||||
{
|
||||
url: NOT_OK_URL,
|
||||
key: "Blocked_ResponseNotOk",
|
||||
shouldRecorded: true,
|
||||
},
|
||||
{
|
||||
url: UNKNOWN_URL,
|
||||
key: "Allowed_FailtoGetMIMEType",
|
||||
shouldRecorded: true,
|
||||
},
|
||||
{
|
||||
url: IMAGE_UNKNOWN_URL,
|
||||
key: "Blocked_ContentTypeBeginsWithImageOrVideoOrAudio",
|
||||
shouldRecorded: true,
|
||||
},
|
||||
{
|
||||
url: MEDIA_URL,
|
||||
key: "Allowed_SniffAsImageOrAudioOrVideo",
|
||||
media: true,
|
||||
shouldRecorded: true,
|
||||
loadType: "media",
|
||||
},
|
||||
{
|
||||
url: MEDIA_206_URL,
|
||||
key: "Allowed_SniffAsImageOrAudioOrVideo",
|
||||
media: true,
|
||||
shouldRecorded: true,
|
||||
loadType: "media",
|
||||
},
|
||||
{
|
||||
url: MEDIA_INVALID_PARTIAL_URL,
|
||||
key: "Blocked_InvaliidPartialResponse",
|
||||
media: true,
|
||||
shouldRecorded: true,
|
||||
loadType: "media",
|
||||
},
|
||||
{
|
||||
url: MEDIA_NOT_200OR206_URL,
|
||||
key: "Blocked_Not200Or206",
|
||||
media: true,
|
||||
shouldRecorded: true,
|
||||
loadType: "media",
|
||||
},
|
||||
{
|
||||
url: IMAGE_UNKNOWN_DECOEDER_URL,
|
||||
key: "Allowed_SniffAsImageOrAudioOrVideo",
|
||||
shouldRecorded: true,
|
||||
},
|
||||
{
|
||||
url: SUBDOCUMENT_URL,
|
||||
key: "Allowed_NotImplementOrPass",
|
||||
shouldRecorded: false,
|
||||
loadType: "iframe",
|
||||
},
|
||||
{
|
||||
url: IMAGE_URL,
|
||||
key: "Allowed_SniffAsImageOrAudioOrVideo",
|
||||
shouldRecorded: false,
|
||||
loadType: "object",
|
||||
},
|
||||
{
|
||||
url: SAME_ORIGIN_OBJECT_URL,
|
||||
key: "Allowed_SniffAsImageOrAudioOrVideo",
|
||||
shouldRecorded: false,
|
||||
loadType: "object",
|
||||
},
|
||||
{
|
||||
url: IMAGE_URL,
|
||||
key: "Allowed_SniffAsImageOrAudioOrVideo",
|
||||
shouldRecorded: false,
|
||||
loadType: "embed",
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -111,10 +151,10 @@ add_task(async function() {
|
|||
|
||||
await SpecialPowers.spawn(
|
||||
browser,
|
||||
[testcase.url, testcase.media],
|
||||
async (url, media) => {
|
||||
[testcase.url, testcase.loadType, testcase.iframe],
|
||||
async (url, loadType, iframe) => {
|
||||
try {
|
||||
if (media) {
|
||||
if (loadType == "media") {
|
||||
const audio = content.document.createElement("audio");
|
||||
audio.src = url;
|
||||
content.document.body.appendChild(audio);
|
||||
|
@ -127,9 +167,43 @@ add_task(async function() {
|
|||
res();
|
||||
};
|
||||
});
|
||||
} else {
|
||||
await content.window.fetch(url);
|
||||
return;
|
||||
}
|
||||
if (loadType == "iframe") {
|
||||
const subframe = content.document.createElement("iframe");
|
||||
subframe.src = url;
|
||||
const onloadPromise = new Promise(res => {
|
||||
subframe.onload = res;
|
||||
});
|
||||
content.document.body.appendChild(subframe);
|
||||
await onloadPromise;
|
||||
content.document.body.removeChild(subframe);
|
||||
return;
|
||||
}
|
||||
if (loadType == "object") {
|
||||
const object = content.document.createElement("object");
|
||||
object.data = url;
|
||||
const onloadPromise = new Promise(res => {
|
||||
object.onload = res;
|
||||
});
|
||||
content.document.body.appendChild(object);
|
||||
await onloadPromise;
|
||||
content.document.body.removeChild(object);
|
||||
return;
|
||||
}
|
||||
if (loadType == "embed") {
|
||||
const embed = content.document.createElement("embed");
|
||||
embed.src = url;
|
||||
const onloadPromise = new Promise(res => {
|
||||
embed.onload = res;
|
||||
});
|
||||
content.document.body.appendChild(embed);
|
||||
await onloadPromise;
|
||||
content.document.body.removeChild(embed);
|
||||
return;
|
||||
}
|
||||
|
||||
await content.window.fetch(url, { mode: "no-cors" });
|
||||
} catch (e) {
|
||||
/* Ignore result */
|
||||
}
|
||||
|
@ -145,7 +219,14 @@ add_task(async function() {
|
|||
keys = [testcase.key];
|
||||
}
|
||||
for (let key of keys) {
|
||||
ok(snapshot.hasOwnProperty(key), `Should have recorded key ${key}`);
|
||||
if (testcase.shouldRecorded) {
|
||||
ok(snapshot.hasOwnProperty(key), `Should have recorded key ${key}`);
|
||||
} else {
|
||||
ok(
|
||||
!snapshot.hasOwnProperty(key),
|
||||
`Should not have recorded key ${key}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
</head>
|
||||
|
||||
<html>
|
||||
<body>
|
||||
<p>Dummy Page</p>
|
||||
<script>
|
||||
let foo = async () => {
|
||||
let url = "https://example.org/browser/netwerk/test/browser/res_img.png";
|
||||
await fetch(url, { mode: "no-cors" });
|
||||
}
|
||||
foo();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
</head>
|
||||
|
||||
<html>
|
||||
<body>
|
||||
<p>Dummy Page</p>
|
||||
</body>
|
||||
</html>
|
Загрузка…
Ссылка в новой задаче