mirror of
https://github.com/servo/servo.git
synced 2025-10-01 17:19:16 +01:00
html: Allow legacy referrer policies only for <meta> referrer (#39506)
Follow the HTML specification and allow to use legacy referrer policies (never/default/always/origin-when-crossorigin) only with 'meta' referrer. See https://html.spec.whatwg.org/multipage/#meta-referrer (step 5) While for another HTML elements with 'referrerpolicy' content attribute (https://html.spec.whatwg.org/multipage/#referrer-policy-attribute) and for 'Referrer-Policy' HTTP header (https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-header-dfn) the referrer policy should be determine from the standard policy tokens (https://w3c.github.io/webappsec-referrer-policy/#referrer-policy). So unknown policy values (legacy from meta-referrer) will be ignored and determine as 'ReferrerPolicy::EmptyString'. Testing: No changes Fixes: #36833 Signed-off-by: Andrei Volykhin <andrei.volykhin@gmail.com>
This commit is contained in:
parent
f724651e1a
commit
6a1a3aea08
8 changed files with 59 additions and 45 deletions
|
@ -22,7 +22,6 @@ use constellation_traits::{NavigationHistoryBehavior, ScriptToConstellationMessa
|
|||
use content_security_policy::sandboxing_directive::SandboxingFlagSet;
|
||||
use content_security_policy::{CspList, PolicyDisposition};
|
||||
use cookie::Cookie;
|
||||
use cssparser::match_ignore_ascii_case;
|
||||
use data_url::mime::Mime;
|
||||
use devtools_traits::ScriptToDevtoolsControlMsg;
|
||||
use dom_struct::dom_struct;
|
||||
|
@ -6003,21 +6002,6 @@ fn update_with_current_instant(marker: &Cell<Option<CrossProcessInstant>>) {
|
|||
}
|
||||
}
|
||||
|
||||
/// <https://w3c.github.io/webappsec-referrer-policy/#determine-policy-for-token>
|
||||
pub(crate) fn determine_policy_for_token(token: &str) -> ReferrerPolicy {
|
||||
match_ignore_ascii_case! { token,
|
||||
"never" | "no-referrer" => ReferrerPolicy::NoReferrer,
|
||||
"no-referrer-when-downgrade" => ReferrerPolicy::NoReferrerWhenDowngrade,
|
||||
"origin" => ReferrerPolicy::Origin,
|
||||
"same-origin" => ReferrerPolicy::SameOrigin,
|
||||
"strict-origin" => ReferrerPolicy::StrictOrigin,
|
||||
"default" | "strict-origin-when-cross-origin" => ReferrerPolicy::StrictOriginWhenCrossOrigin,
|
||||
"origin-when-cross-origin" => ReferrerPolicy::OriginWhenCrossOrigin,
|
||||
"always" | "unsafe-url" => ReferrerPolicy::UnsafeUrl,
|
||||
_ => ReferrerPolicy::EmptyString,
|
||||
}
|
||||
}
|
||||
|
||||
/// Specifies the type of focus event that is sent to a pipeline
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub(crate) enum FocusType {
|
||||
|
|
|
@ -106,7 +106,7 @@ use crate::dom::customelementregistry::{
|
|||
CallbackReaction, CustomElementDefinition, CustomElementReaction, CustomElementState,
|
||||
is_valid_custom_element_name,
|
||||
};
|
||||
use crate::dom::document::{Document, LayoutDocumentHelpers, determine_policy_for_token};
|
||||
use crate::dom::document::{Document, LayoutDocumentHelpers};
|
||||
use crate::dom::documentfragment::DocumentFragment;
|
||||
use crate::dom::domrect::DOMRect;
|
||||
use crate::dom::domrectlist::DOMRectList;
|
||||
|
@ -5481,7 +5481,7 @@ pub(crate) fn reflect_referrer_policy_attribute(element: &Element) -> DOMString
|
|||
pub(crate) fn referrer_policy_for_element(element: &Element) -> ReferrerPolicy {
|
||||
element
|
||||
.get_attribute(&ns!(), &local_name!("referrerpolicy"))
|
||||
.map(|attribute| determine_policy_for_token(&attribute.value()))
|
||||
.map(|attribute| ReferrerPolicy::from(&**attribute.value()))
|
||||
.unwrap_or(element.owner_document().get_referrer_policy())
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ use crate::dom::bindings::inheritance::Castable;
|
|||
use crate::dom::bindings::reflector::DomGlobal;
|
||||
use crate::dom::bindings::root::{DomRoot, LayoutDom, MutNullableDom};
|
||||
use crate::dom::bindings::str::{DOMString, USVString};
|
||||
use crate::dom::document::{Document, determine_policy_for_token};
|
||||
use crate::dom::document::Document;
|
||||
use crate::dom::domtokenlist::DOMTokenList;
|
||||
use crate::dom::element::{
|
||||
AttributeMutation, Element, LayoutElementHelpers, reflect_referrer_policy_attribute,
|
||||
|
@ -336,7 +336,7 @@ impl HTMLIFrameElement {
|
|||
// Note: despite not being explicitly stated in the spec steps, this falls back to
|
||||
// document's referrer policy here because it satisfies the expectations that when unset,
|
||||
// the iframe should inherit the referrer policy of its parent
|
||||
let referrer_policy = match determine_policy_for_token(referrer_policy_token.str()) {
|
||||
let referrer_policy = match ReferrerPolicy::from(referrer_policy_token.str()) {
|
||||
ReferrerPolicy::EmptyString => document.get_referrer_policy(),
|
||||
policy => policy,
|
||||
};
|
||||
|
|
|
@ -59,7 +59,7 @@ use crate::dom::bindings::reflector::DomGlobal;
|
|||
use crate::dom::bindings::root::{DomRoot, LayoutDom, MutNullableDom};
|
||||
use crate::dom::bindings::str::{DOMString, USVString};
|
||||
use crate::dom::csp::{GlobalCspReporting, Violation};
|
||||
use crate::dom::document::{Document, determine_policy_for_token};
|
||||
use crate::dom::document::Document;
|
||||
use crate::dom::element::{
|
||||
AttributeMutation, CustomElementCreationMode, Element, ElementCreator, LayoutElementHelpers,
|
||||
cors_setting_for_element, referrer_policy_for_element, reflect_cross_origin_attribute,
|
||||
|
@ -1872,15 +1872,10 @@ impl VirtualMethods for HTMLImageElement {
|
|||
// The element's referrerpolicy attribute's state is changed.
|
||||
let referrer_policy_state_changed = match mutation {
|
||||
AttributeMutation::Removed | AttributeMutation::Set(None) => {
|
||||
let referrer_policy = determine_policy_for_token(&attr.value());
|
||||
|
||||
referrer_policy != ReferrerPolicy::EmptyString
|
||||
ReferrerPolicy::from(&**attr.value()) != ReferrerPolicy::EmptyString
|
||||
},
|
||||
AttributeMutation::Set(Some(old_value)) => {
|
||||
let new_referrer_policy = determine_policy_for_token(&attr.value());
|
||||
let old_referrer_policy = determine_policy_for_token(old_value);
|
||||
|
||||
new_referrer_policy != old_referrer_policy
|
||||
ReferrerPolicy::from(&**attr.value()) != ReferrerPolicy::from(&**old_value)
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ use compositing_traits::viewport_description::ViewportDescription;
|
|||
use dom_struct::dom_struct;
|
||||
use html5ever::{LocalName, Prefix, local_name, ns};
|
||||
use js::rust::HandleObject;
|
||||
use net_traits::ReferrerPolicy;
|
||||
use servo_config::pref;
|
||||
use style::str::HTML_SPACE_CHARACTERS;
|
||||
|
||||
|
@ -17,7 +18,7 @@ use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
|
|||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::document::{Document, determine_policy_for_token};
|
||||
use crate::dom::document::Document;
|
||||
use crate::dom::element::{AttributeMutation, Element};
|
||||
use crate::dom::html::htmlelement::HTMLElement;
|
||||
use crate::dom::html::htmlheadelement::HTMLHeadElement;
|
||||
|
@ -97,28 +98,32 @@ impl HTMLMetaElement {
|
|||
// From spec: For historical reasons, unlike other standard metadata names, the processing model for referrer
|
||||
// is not responsive to element removals, and does not use tree order. Only the most-recently-inserted or
|
||||
// most-recently-modified meta element in this state has an effect.
|
||||
// 1. If element is not in a document tree, then return.
|
||||
// Step 1. If element is not in a document tree, then return.
|
||||
let meta_node = self.upcast::<Node>();
|
||||
if !meta_node.is_in_a_document_tree() {
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. If element does not have a name attribute whose value is an ASCII case-insensitive match for "referrer",
|
||||
// then return.
|
||||
// Step 2. If element does not have a name attribute whose value is an ASCII
|
||||
// case-insensitive match for "referrer", then return.
|
||||
if self.upcast::<Element>().get_name() != Some(atom!("referrer")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. If element does not have a content attribute, or that attribute's value is the empty string, then return.
|
||||
let content = self
|
||||
// Step 3. If element does not have a content attribute, or that attribute's value is the
|
||||
// empty string, then return.
|
||||
if let Some(content) = self
|
||||
.upcast::<Element>()
|
||||
.get_attribute(&ns!(), &local_name!("content"));
|
||||
if let Some(attr) = content {
|
||||
let attr = attr.value();
|
||||
let attr_val = attr.trim();
|
||||
if !attr_val.is_empty() {
|
||||
doc.set_referrer_policy(determine_policy_for_token(attr_val));
|
||||
}
|
||||
.get_attribute(&ns!(), &local_name!("content"))
|
||||
.filter(|attr| !attr.value().is_empty())
|
||||
{
|
||||
// Step 4. Let value be the value of element's content attribute, converted to ASCII
|
||||
// lowercase.
|
||||
// Step 5. If value is one of the values given in the first column of the following
|
||||
// table, then set value to the value given in the second column:
|
||||
// Step 6. If value is a referrer policy, then set element's node document's policy
|
||||
// container's referrer policy to policy.
|
||||
doc.set_referrer_policy(ReferrerPolicy::from_with_legacy(&content.value()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ use crate::dom::bindings::refcounted::Trusted;
|
|||
use crate::dom::bindings::reflector::DomGlobal;
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::csp::{GlobalCspReporting, Violation};
|
||||
use crate::dom::document::{Document, determine_policy_for_token};
|
||||
use crate::dom::document::Document;
|
||||
use crate::dom::element::Element;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::medialist::MediaList;
|
||||
|
@ -100,7 +100,7 @@ impl LinkProcessingOptions {
|
|||
// Step 4. If attribs["referrerpolicy"] exists and is an ASCII case-insensitive match for
|
||||
// some referrer policy, then set options's referrer policy to that referrer policy.
|
||||
if let Some(referrer_policy) = link_object.value_for_key_in_link_header("referrerpolicy") {
|
||||
self.referrer_policy = determine_policy_for_token(referrer_policy);
|
||||
self.referrer_policy = ReferrerPolicy::from(referrer_policy);
|
||||
}
|
||||
// Step 5. If attribs["nonce"] exists, then set options's nonce to attribs["nonce"].
|
||||
if let Some(nonce) = link_object.value_for_key_in_link_header("nonce") {
|
||||
|
|
|
@ -24,7 +24,7 @@ use servo_url::{ImmutableOrigin, ServoUrl};
|
|||
|
||||
use crate::dom::bindings::reflector::DomGlobal;
|
||||
use crate::dom::bindings::trace::{CustomTraceable, JSTraceable};
|
||||
use crate::dom::document::{Document, determine_policy_for_token};
|
||||
use crate::dom::document::Document;
|
||||
use crate::dom::html::htmlscriptelement::script_fetch_request;
|
||||
use crate::dom::processingoptions::determine_cors_settings_for_token;
|
||||
use crate::fetch::create_a_potential_cors_request;
|
||||
|
@ -263,7 +263,7 @@ impl PrefetchSink {
|
|||
|
||||
fn get_referrer_policy(&self, tag: &Tag, name: LocalName) -> ReferrerPolicy {
|
||||
self.get_attr(tag, name)
|
||||
.map(|attr| determine_policy_for_token(&attr.value))
|
||||
.map(|attr| ReferrerPolicy::from(&*attr.value))
|
||||
.unwrap_or(self.referrer_policy)
|
||||
}
|
||||
|
||||
|
|
|
@ -133,6 +133,19 @@ pub enum ReferrerPolicy {
|
|||
}
|
||||
|
||||
impl ReferrerPolicy {
|
||||
/// <https://html.spec.whatwg.org/multipage/#meta-referrer>
|
||||
pub fn from_with_legacy(value: &str) -> Self {
|
||||
// Step 5. If value is one of the values given in the first column of the following table,
|
||||
// then set value to the value given in the second column:
|
||||
match value.to_ascii_lowercase().as_str() {
|
||||
"never" => ReferrerPolicy::NoReferrer,
|
||||
"default" => ReferrerPolicy::StrictOriginWhenCrossOrigin,
|
||||
"always" => ReferrerPolicy::UnsafeUrl,
|
||||
"origin-when-crossorigin" => ReferrerPolicy::OriginWhenCrossOrigin,
|
||||
_ => ReferrerPolicy::from(value),
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://w3c.github.io/webappsec-referrer-policy/#parse-referrer-policy-from-header>
|
||||
pub fn parse_header_for_response(headers: &Option<Serde<HeaderMap>>) -> Self {
|
||||
// Step 4. Return policy.
|
||||
|
@ -145,6 +158,23 @@ impl ReferrerPolicy {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<&str> for ReferrerPolicy {
|
||||
/// <https://html.spec.whatwg.org/multipage/#referrer-policy-attribute>
|
||||
fn from(value: &str) -> Self {
|
||||
match value.to_ascii_lowercase().as_str() {
|
||||
"no-referrer" => ReferrerPolicy::NoReferrer,
|
||||
"no-referrer-when-downgrade" => ReferrerPolicy::NoReferrerWhenDowngrade,
|
||||
"origin" => ReferrerPolicy::Origin,
|
||||
"same-origin" => ReferrerPolicy::SameOrigin,
|
||||
"strict-origin" => ReferrerPolicy::StrictOrigin,
|
||||
"strict-origin-when-cross-origin" => ReferrerPolicy::StrictOriginWhenCrossOrigin,
|
||||
"origin-when-cross-origin" => ReferrerPolicy::OriginWhenCrossOrigin,
|
||||
"unsafe-url" => ReferrerPolicy::UnsafeUrl,
|
||||
_ => ReferrerPolicy::EmptyString,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ReferrerPolicy {
|
||||
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let string = match self {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue