mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-07 18:04:46 +00:00
Bug 1223838 - Fix wrong policy associated with empty string. r=fkiefer,hsivonen
MozReview-Commit-ID: 7kFH39cegmH
This commit is contained in:
parent
8e14007b6d
commit
4b7ad0e2c5
@ -3781,15 +3781,17 @@ nsDocument::SetHeaderData(nsIAtom* aHeaderField, const nsAString& aData)
|
||||
|
||||
// Referrer policy spec says to ignore any empty referrer policies.
|
||||
if (aHeaderField == nsGkAtoms::referrer && !aData.IsEmpty()) {
|
||||
ReferrerPolicy policy = mozilla::net::ReferrerPolicyFromString(aData);
|
||||
|
||||
// Referrer policy spec (section 6.1) says that we always use the newest
|
||||
// referrer policy we find
|
||||
mReferrerPolicy = policy;
|
||||
mReferrerPolicySet = true;
|
||||
ReferrerPolicy policy = mozilla::net::ReferrerPolicyFromString(aData);
|
||||
// If policy is not the empty string, then set element's node document's
|
||||
// referrer policy to policy
|
||||
if (policy != mozilla::net::RP_Unset) {
|
||||
// Referrer policy spec (section 6.1) says that we always use the newest
|
||||
// referrer policy we find
|
||||
mReferrerPolicy = policy;
|
||||
mReferrerPolicySet = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::TryChannelCharset(nsIChannel *aChannel,
|
||||
int32_t& aCharsetSource,
|
||||
|
@ -93,10 +93,11 @@ function createTestPage2(aHead, aPolicy, aName) {
|
||||
</html>';
|
||||
}
|
||||
|
||||
function createTestPage3(aPolicy, aName) {
|
||||
function createTestPage3(aHead, aPolicy, aName) {
|
||||
return '<!DOCTYPE HTML>\n\
|
||||
<html>\n\
|
||||
<body>\n\
|
||||
<html>'+
|
||||
aHead +
|
||||
'<body>\n\
|
||||
<script>' +
|
||||
'var image = new Image();\n\
|
||||
image.src = "' + createTestUrl(aPolicy, "test", aName, "image") + '";\n\
|
||||
@ -111,10 +112,11 @@ function createTestPage3(aPolicy, aName) {
|
||||
</html>';
|
||||
}
|
||||
|
||||
function createTestPage4(aPolicy, aName) {
|
||||
function createTestPage4(aHead, aPolicy, aName) {
|
||||
return '<!DOCTYPE HTML>\n\
|
||||
<html>\n\
|
||||
<body>\n\
|
||||
<html>'+
|
||||
aHead +
|
||||
'<body>\n\
|
||||
<script>' +
|
||||
'var image = new Image();\n\
|
||||
image.referrerPolicy = "' + aPolicy + '";\n\
|
||||
@ -129,6 +131,23 @@ function createTestPage4(aPolicy, aName) {
|
||||
</html>';
|
||||
}
|
||||
|
||||
function createSetAttributeTest1(aPolicy, aImgPolicy, aName) {
|
||||
var headString = '<head>';
|
||||
headString += '<meta name="referrer" content="' + aPolicy + '">';
|
||||
headString += '<script></script>';
|
||||
|
||||
return createTestPage3(headString, aImgPolicy, aName);
|
||||
}
|
||||
|
||||
function createSetAttributeTest2(aPolicy, aImgPolicy, aName) {
|
||||
var headString = '<head>';
|
||||
headString += '<meta name="referrer" content="' + aPolicy + '">';
|
||||
headString += '<script></script>';
|
||||
|
||||
return createTestPage4(headString, aImgPolicy, aName);
|
||||
}
|
||||
|
||||
|
||||
function createTest4(aPolicy, aName) {
|
||||
var headString = '<head>';
|
||||
headString += '<meta name="referrer" content="' + aPolicy + '">';
|
||||
@ -256,19 +275,21 @@ function handleRequest(request, response) {
|
||||
|
||||
if (action === 'generate-setAttribute-test1') {
|
||||
// ?action=generate-setAttribute-test1&policy=b64-encoded-string&name=name
|
||||
var policy = unescape(params[1].split('=')[1]);
|
||||
var name = unescape(params[2].split('=')[1]);
|
||||
var imgPolicy = unescape(params[1].split('=')[1]);
|
||||
var policy = unescape(params[2].split('=')[1]);
|
||||
var name = unescape(params[3].split('=')[1]);
|
||||
|
||||
response.write(createTestPage3(policy, name));
|
||||
response.write(createSetAttributeTest1(policy, imgPolicy, name));
|
||||
return;
|
||||
}
|
||||
|
||||
if (action === 'generate-setAttribute-test2') {
|
||||
// ?action=generate-setAttribute-test2&policy=b64-encoded-string&name=name
|
||||
var policy = unescape(params[1].split('=')[1]);
|
||||
var name = unescape(params[2].split('=')[1]);
|
||||
var imgPolicy = unescape(params[1].split('=')[1]);
|
||||
var policy = unescape(params[2].split('=')[1]);
|
||||
var name = unescape(params[3].split('=')[1]);
|
||||
|
||||
response.write(createTestPage4(policy, name));
|
||||
response.write(createSetAttributeTest2(policy, imgPolicy, name));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -584,7 +584,6 @@ skip-if = buildapp == 'b2g' # b2g (https://example.com not working bug 1162353)
|
||||
skip-if = buildapp == 'b2g' # b2g (https://example.com not working bug 1162353)
|
||||
[test_bug704320_policyset.html]
|
||||
[test_bug704320_policyset2.html]
|
||||
skip-if = os == "mac" # fails intermittently - bug 1101288
|
||||
[test_bug704320_preload.html]
|
||||
[test_bug707142.html]
|
||||
[test_bug708620.html]
|
||||
|
@ -40,12 +40,12 @@ var tests = (function() {
|
||||
yield checkIndividualResults("default", ["full"]);
|
||||
|
||||
// check invalid policy
|
||||
// According to the spec section 6.4, if there is a policy token
|
||||
// and it is not one of the expected tokens, "No Referrer"
|
||||
// should be the policy used.
|
||||
// According to the spec section Determine token's Policy,if there is a policy
|
||||
// token and it is not one of the expected tokens, Empty string should be the
|
||||
// policy used.
|
||||
yield resetCounter();
|
||||
yield iframe.src = sjs + "&policy=" + escape('invalid-policy');
|
||||
yield checkIndividualResults("invalid", ["none"]);
|
||||
yield checkIndividualResults("invalid", ["full"]);
|
||||
|
||||
// whitespace checks.
|
||||
// according to the spec section 4.1, the content attribute's value
|
||||
@ -84,6 +84,11 @@ var tests = (function() {
|
||||
yield iframe.src = sjs + "&policy=" + escape('no-referrer');
|
||||
yield checkIndividualResults("no-referrer", ["none"]);
|
||||
|
||||
// Case insensitive
|
||||
yield resetCounter();
|
||||
yield iframe.src = sjs + "&policy=" + escape('\f OrigIn');
|
||||
yield checkIndividualResults("origin case insensitive", ["origin"]);
|
||||
|
||||
// complete. Be sure to yield so we don't call this twice.
|
||||
yield SimpleTest.finish();
|
||||
})();
|
||||
|
@ -151,15 +151,29 @@ var tests = (function() {
|
||||
yield resetState();
|
||||
sjs = "/tests/dom/base/test/img_referrer_testserver.sjs?action=generate-setAttribute-test1";
|
||||
name = 'set-referrer-policy-attribute-before-src';
|
||||
yield iframe.src = sjs + "&policy=" + escape('no-referrer') + "&name=" + name;
|
||||
yield iframe.src = sjs + "&imgPolicy=" + escape('no-referrer') + "&policy=" + escape('unsafe-url') + "&name=" + name;
|
||||
yield checkIndividualResults("no-referrer in img", ["none"], [name]);
|
||||
|
||||
yield resetState();
|
||||
sjs = "/tests/dom/base/test/img_referrer_testserver.sjs?action=generate-setAttribute-test2";
|
||||
name = 'set-referrer-policy-attribute-after-src';
|
||||
yield iframe.src = sjs + "&policy=" + escape('no-referrer') + "&name=" + name;
|
||||
yield iframe.src = sjs + "&imgPolicy=" + escape('no-referrer') + "&policy=" + escape('unsafe-url') + "&name=" + name;
|
||||
yield checkIndividualResults("no-referrer in img", ["none"], [name]);
|
||||
|
||||
yield resetState();
|
||||
sjs =
|
||||
"/tests/dom/base/test/img_referrer_testserver.sjs?action=generate-setAttribute-test2";
|
||||
name = 'set-invalid-referrer-policy-attribute-before-src-invalid';
|
||||
yield iframe.src = sjs + "&imgPolicy=" + escape('invalid') + "&policy=" + escape('unsafe-url') + "&name=" + name;
|
||||
yield checkIndividualResults("unsafe-url in meta, invalid in img", ["full"], [name]);
|
||||
|
||||
yield resetState();
|
||||
sjs =
|
||||
"/tests/dom/base/test/img_referrer_testserver.sjs?action=generate-setAttribute-test2";
|
||||
name = 'set-invalid-referrer-policy-attribute-before-src-invalid';
|
||||
yield iframe.src = sjs + "&imgPolicy=" + escape('default') + "&policy=" + escape('unsafe-url') + "&name=" + name;
|
||||
yield checkIndividualResults("unsafe-url in meta, default in img", ["full"], [name]);
|
||||
|
||||
// complete. Be sure to yield so we don't call this twice.
|
||||
yield SimpleTest.finish();
|
||||
})();
|
||||
|
@ -555,8 +555,10 @@ HTMLImageElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
} else if (aName == nsGkAtoms::referrerpolicy &&
|
||||
aNameSpaceID == kNameSpaceID_None &&
|
||||
aNotify) {
|
||||
ReferrerPolicy referrerPolicy = ReferrerPolicyFromString(aValue);
|
||||
if (!InResponsiveMode() && referrerPolicy != GetImageReferrerPolicy()) {
|
||||
ReferrerPolicy referrerPolicy = AttributeReferrerPolicyFromString(aValue);
|
||||
if (!InResponsiveMode() &&
|
||||
referrerPolicy != RP_Unset &&
|
||||
referrerPolicy != GetImageReferrerPolicy()) {
|
||||
// XXX: Bug 1076583 - We still use the older synchronous algorithm
|
||||
// Because referrerPolicy is not treated as relevant mutations, setting
|
||||
// the attribute will neither trigger a reload nor update the referrer
|
||||
|
@ -342,8 +342,21 @@ nsCSPContext::GetReferrerPolicy(uint32_t* outPolicy, bool* outIsSet)
|
||||
// an empty string in refpol means it wasn't set (that's the default in
|
||||
// nsCSPPolicy).
|
||||
if (!refpol.IsEmpty()) {
|
||||
// if there are two policies that specify a referrer policy, then they
|
||||
// Referrer Directive in CSP is no more used and going to be replaced by
|
||||
// Referrer-Policy HTTP header. But we still keep using referrer directive,
|
||||
// and would remove it later.
|
||||
// Referrer Directive specs is not fully compliant with new referrer policy
|
||||
// specs. What we are using here:
|
||||
// - If the value of the referrer directive is invalid, the user agent
|
||||
// should set the referrer policy to no-referrer.
|
||||
// - If there are two policies that specify a referrer policy, then they
|
||||
// must agree or the employed policy is no-referrer.
|
||||
if (!mozilla::net::IsValidReferrerPolicy(refpol)) {
|
||||
*outPolicy = mozilla::net::RP_No_Referrer;
|
||||
*outIsSet = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
uint32_t currentPolicy = mozilla::net::ReferrerPolicyFromString(refpol);
|
||||
if (*outIsSet && previousPolicy != currentPolicy) {
|
||||
*outPolicy = mozilla::net::RP_No_Referrer;
|
||||
|
@ -2022,7 +2022,8 @@ imgLoader::LoadImageXPCOM(nsIURI* aURI,
|
||||
nsresult rv = LoadImage(aURI,
|
||||
aInitialDocumentURI,
|
||||
aReferrerURI,
|
||||
refpol,
|
||||
refpol == mozilla::net::RP_Unset ?
|
||||
mozilla::net::RP_Default : refpol,
|
||||
aLoadingPrincipal,
|
||||
aLoadGroup,
|
||||
aObserver,
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsIHttpChannel.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
|
||||
namespace mozilla { namespace net {
|
||||
|
||||
@ -27,7 +28,8 @@ enum ReferrerPolicy {
|
||||
/* spec tokens: always unsafe-url */
|
||||
RP_Unsafe_URL = nsIHttpChannel::REFERRER_POLICY_UNSAFE_URL,
|
||||
|
||||
/* referrer policy is not set */
|
||||
/* spec tokens: empty string */
|
||||
/* The empty string "" corresponds to no referrer policy, or unset policy */
|
||||
RP_Unset = nsIHttpChannel::REFERRER_POLICY_UNSET,
|
||||
};
|
||||
|
||||
@ -53,71 +55,89 @@ const char kRPS_Unsafe_URL[] = "unsafe-url";
|
||||
inline ReferrerPolicy
|
||||
ReferrerPolicyFromString(const nsAString& content)
|
||||
{
|
||||
// This is implemented step by step as described in the Referrer Policy
|
||||
// specification, section 6.4 "Determine token's Policy".
|
||||
if (content.LowerCaseEqualsLiteral(kRPS_Never) ||
|
||||
content.LowerCaseEqualsLiteral(kRPS_No_Referrer)) {
|
||||
if (content.IsEmpty()) {
|
||||
return RP_No_Referrer;
|
||||
}
|
||||
if (content.LowerCaseEqualsLiteral(kRPS_Origin)) {
|
||||
|
||||
nsString lowerContent(content);
|
||||
ToLowerCase(lowerContent);
|
||||
// This is implemented step by step as described in the Referrer Policy
|
||||
// specification, section "Determine token's Policy".
|
||||
if (lowerContent.EqualsLiteral(kRPS_Never) ||
|
||||
lowerContent.EqualsLiteral(kRPS_No_Referrer)) {
|
||||
return RP_No_Referrer;
|
||||
}
|
||||
if (lowerContent.EqualsLiteral(kRPS_Origin)) {
|
||||
return RP_Origin;
|
||||
}
|
||||
if (content.LowerCaseEqualsLiteral(kRPS_Default) ||
|
||||
content.LowerCaseEqualsLiteral(kRPS_No_Referrer_When_Downgrade)) {
|
||||
if (lowerContent.EqualsLiteral(kRPS_Default) ||
|
||||
lowerContent.EqualsLiteral(kRPS_No_Referrer_When_Downgrade)) {
|
||||
return RP_No_Referrer_When_Downgrade;
|
||||
}
|
||||
if (content.LowerCaseEqualsLiteral(kRPS_Origin_When_Cross_Origin) ||
|
||||
content.LowerCaseEqualsLiteral(kRPS_Origin_When_Crossorigin)) {
|
||||
if (lowerContent.EqualsLiteral(kRPS_Origin_When_Cross_Origin) ||
|
||||
lowerContent.EqualsLiteral(kRPS_Origin_When_Crossorigin)) {
|
||||
return RP_Origin_When_Crossorigin;
|
||||
}
|
||||
if (content.LowerCaseEqualsLiteral(kRPS_Always) ||
|
||||
content.LowerCaseEqualsLiteral(kRPS_Unsafe_URL)) {
|
||||
if (lowerContent.EqualsLiteral(kRPS_Always) ||
|
||||
lowerContent.EqualsLiteral(kRPS_Unsafe_URL)) {
|
||||
return RP_Unsafe_URL;
|
||||
}
|
||||
// Spec says if none of the previous match, use No_Referrer.
|
||||
return RP_No_Referrer;
|
||||
// Spec says if none of the previous match, use empty string.
|
||||
return RP_Unset;
|
||||
|
||||
}
|
||||
|
||||
inline bool
|
||||
IsValidReferrerPolicy(const nsAString& content)
|
||||
{
|
||||
return content.LowerCaseEqualsLiteral(kRPS_Never)
|
||||
|| content.LowerCaseEqualsLiteral(kRPS_No_Referrer)
|
||||
|| content.LowerCaseEqualsLiteral(kRPS_Origin)
|
||||
|| content.LowerCaseEqualsLiteral(kRPS_Default)
|
||||
|| content.LowerCaseEqualsLiteral(kRPS_No_Referrer_When_Downgrade)
|
||||
|| content.LowerCaseEqualsLiteral(kRPS_Origin_When_Cross_Origin)
|
||||
|| content.LowerCaseEqualsLiteral(kRPS_Origin_When_Crossorigin)
|
||||
|| content.LowerCaseEqualsLiteral(kRPS_Always)
|
||||
|| content.LowerCaseEqualsLiteral(kRPS_Unsafe_URL);
|
||||
}
|
||||
if (content.IsEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool
|
||||
IsValidAttributeReferrerPolicy(const nsAString& aContent)
|
||||
{
|
||||
return aContent.LowerCaseEqualsLiteral(kRPS_No_Referrer)
|
||||
|| aContent.LowerCaseEqualsLiteral(kRPS_Origin)
|
||||
|| aContent.LowerCaseEqualsLiteral(kRPS_No_Referrer_When_Downgrade)
|
||||
|| aContent.LowerCaseEqualsLiteral(kRPS_Origin_When_Cross_Origin)
|
||||
|| aContent.LowerCaseEqualsLiteral(kRPS_Unsafe_URL);
|
||||
nsString lowerContent(content);
|
||||
ToLowerCase(lowerContent);
|
||||
|
||||
return lowerContent.EqualsLiteral(kRPS_Never)
|
||||
|| lowerContent.EqualsLiteral(kRPS_No_Referrer)
|
||||
|| lowerContent.EqualsLiteral(kRPS_Origin)
|
||||
|| lowerContent.EqualsLiteral(kRPS_Default)
|
||||
|| lowerContent.EqualsLiteral(kRPS_No_Referrer_When_Downgrade)
|
||||
|| lowerContent.EqualsLiteral(kRPS_Origin_When_Cross_Origin)
|
||||
|| lowerContent.EqualsLiteral(kRPS_Origin_When_Crossorigin)
|
||||
|| lowerContent.EqualsLiteral(kRPS_Always)
|
||||
|| lowerContent.EqualsLiteral(kRPS_Unsafe_URL);
|
||||
}
|
||||
|
||||
inline ReferrerPolicy
|
||||
AttributeReferrerPolicyFromString(const nsAString& aContent)
|
||||
AttributeReferrerPolicyFromString(const nsAString& content)
|
||||
{
|
||||
// if the referrer attribute string is empty, return RP_Unset
|
||||
if (aContent.IsEmpty()) {
|
||||
// Specs : https://html.spec.whatwg.org/multipage/infrastructure.html#referrer-policy-attribute
|
||||
// Spec says the empty string "" corresponds to no referrer policy, or RP_Unset
|
||||
if (content.IsEmpty()) {
|
||||
return RP_Unset;
|
||||
}
|
||||
// if the referrer attribute string is not empty and contains a valid
|
||||
// referrer policy, return the according enum value
|
||||
if (IsValidAttributeReferrerPolicy(aContent)) {
|
||||
return ReferrerPolicyFromString(aContent);
|
||||
|
||||
nsString lowerContent(content);
|
||||
ToLowerCase(lowerContent);
|
||||
|
||||
if (lowerContent.EqualsLiteral(kRPS_No_Referrer)) {
|
||||
return RP_No_Referrer;
|
||||
}
|
||||
// in any other case the referrer attribute contains an invalid
|
||||
// policy value, we thus return RP_No_Referrer
|
||||
return RP_No_Referrer;
|
||||
if (lowerContent.EqualsLiteral(kRPS_Origin)) {
|
||||
return RP_Origin;
|
||||
}
|
||||
if (lowerContent.EqualsLiteral(kRPS_No_Referrer_When_Downgrade)) {
|
||||
return RP_No_Referrer_When_Downgrade;
|
||||
}
|
||||
if (lowerContent.EqualsLiteral(kRPS_Origin_When_Cross_Origin)) {
|
||||
return RP_Origin_When_Crossorigin;
|
||||
}
|
||||
if (lowerContent.EqualsLiteral(kRPS_Unsafe_URL)) {
|
||||
return RP_Unsafe_URL;
|
||||
}
|
||||
// Spec says invalid value default is empty string state
|
||||
// So, return RP_Unset if none of the previous match, return RP_Unset
|
||||
return RP_Unset;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
|
@ -952,7 +952,8 @@ nsHtml5TreeOpExecutor::PreloadImage(const nsAString& aURL,
|
||||
// if enabled in preferences, use the referrer attribute from the image, if provided
|
||||
bool referrerAttributeEnabled = Preferences::GetBool("network.http.enablePerElementReferrer", true);
|
||||
if (referrerAttributeEnabled) {
|
||||
mozilla::net::ReferrerPolicy imageReferrerPolicy = mozilla::net::ReferrerPolicyFromString(aImageReferrerPolicy);
|
||||
mozilla::net::ReferrerPolicy imageReferrerPolicy =
|
||||
mozilla::net::AttributeReferrerPolicyFromString(aImageReferrerPolicy);
|
||||
if (imageReferrerPolicy != mozilla::net::RP_Unset) {
|
||||
referrerPolicy = imageReferrerPolicy;
|
||||
}
|
||||
@ -1011,8 +1012,21 @@ nsHtml5TreeOpExecutor::SetSpeculationBase(const nsAString& aURL)
|
||||
void
|
||||
nsHtml5TreeOpExecutor::SetSpeculationReferrerPolicy(const nsAString& aReferrerPolicy)
|
||||
{
|
||||
// Specs says:
|
||||
// - Let value be the result of stripping leading and trailing whitespace from
|
||||
// the value of element's content attribute.
|
||||
// - If value is not the empty string, then:
|
||||
if (aReferrerPolicy.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ReferrerPolicy policy = mozilla::net::ReferrerPolicyFromString(aReferrerPolicy);
|
||||
return SetSpeculationReferrerPolicy(policy);
|
||||
// Specs says:
|
||||
// - If policy is not the empty string, then set element's node document's
|
||||
// referrer policy to policy
|
||||
if (policy != mozilla::net::RP_Unset) {
|
||||
SetSpeculationReferrerPolicy(policy);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
Loading…
Reference in New Issue
Block a user