Skip to content

Commit

Permalink
Add meta-referrer support for documents
Browse files Browse the repository at this point in the history
  • Loading branch information
rebstar6 committed Jun 3, 2016
1 parent d0f5a5f commit 687d0cd
Show file tree
Hide file tree
Showing 56 changed files with 136 additions and 263 deletions.
2 changes: 1 addition & 1 deletion components/msg/constellation_msg.rs
Expand Up @@ -358,7 +358,7 @@ pub enum FrameType {

/// [Policies](https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-states)
/// for providing a referrer header for a request
#[derive(HeapSizeOf, Clone, Deserialize, Serialize)]
#[derive(Clone, Copy, Debug, Deserialize, HeapSizeOf, Serialize)]
pub enum ReferrerPolicy {
NoReferrer,
NoRefWhenDowngrade,
Expand Down
18 changes: 12 additions & 6 deletions components/net/http_loader.rs
Expand Up @@ -596,7 +596,8 @@ pub fn modify_request_headers(headers: &mut Headers,
cookie_jar: &Arc<RwLock<CookieStorage>>,
auth_cache: &Arc<RwLock<AuthCache>>,
load_data: &LoadData,
block_cookies: bool) {
block_cookies: bool,
referrer_url: &mut Option<Url>) {
// Ensure that the host header is set from the original url
let host = Host {
hostname: url.host_str().unwrap().to_owned(),
Expand All @@ -617,10 +618,12 @@ pub fn modify_request_headers(headers: &mut Headers,
set_default_accept(headers);
set_default_accept_encoding(headers);

if let Some(referer_val) = determine_request_referrer(headers,
load_data.referrer_policy.clone(),
load_data.referrer_url.clone(),
url.clone()) {
*referrer_url = determine_request_referrer(headers,
load_data.referrer_policy.clone(),
referrer_url.clone(),
url.clone());

if let Some(referer_val) = referrer_url.clone() {
headers.set(Referer(referer_val.into_string()));
}

Expand Down Expand Up @@ -808,6 +811,8 @@ pub fn load<A, B>(load_data: &LoadData,
let mut doc_url = load_data.url.clone();
let mut redirected_to = HashSet::new();
let mut method = load_data.method.clone();
// URL of referrer - to be updated with redirects
let mut referrer_url = load_data.referrer_url.clone();

let mut new_auth_header: Option<Authorization<Basic>> = None;

Expand Down Expand Up @@ -901,7 +906,8 @@ pub fn load<A, B>(load_data: &LoadData,

modify_request_headers(&mut request_headers, &doc_url,
&user_agent, &http_state.cookie_jar,
&http_state.auth_cache, &load_data, block_cookies);
&http_state.auth_cache, &load_data,
block_cookies, &mut referrer_url);

//if there is a new auth header then set the request headers with it
if let Some(ref auth_header) = new_auth_header {
Expand Down
2 changes: 1 addition & 1 deletion components/net_traits/lib.rs
Expand Up @@ -140,7 +140,7 @@ impl LoadData {
credentials_flag: true,
context: context,
referrer_policy: load_origin.referrer_policy(),
referrer_url: load_origin.referrer_url(),
referrer_url: load_origin.referrer_url().clone(),
source: load_origin.request_source()
}
}
Expand Down
26 changes: 22 additions & 4 deletions components/script/dom/document.rs
Expand Up @@ -238,7 +238,7 @@ pub struct Document {
/// The document's origin.
origin: Origin,
/// https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-states
referrer_policy: Option<ReferrerPolicy>,
referrer_policy: Cell<Option<ReferrerPolicy>>,
}

#[derive(JSTraceable, HeapSizeOf)]
Expand Down Expand Up @@ -1700,7 +1700,7 @@ impl Document {
touchpad_pressure_phase: Cell::new(TouchpadPressurePhase::BeforeClick),
origin: origin,
//TODO - setting this for now so no Referer header set
referrer_policy: Some(ReferrerPolicy::NoReferrer),
referrer_policy: Cell::new(Some(ReferrerPolicy::NoReferrer)),
}
}

Expand Down Expand Up @@ -1830,9 +1830,13 @@ impl Document {
}
}

//TODO - for now, returns no-referrer for all until reading in the value
pub fn set_referrer_policy(&self, policy: Option<ReferrerPolicy>) {
self.referrer_policy.set(policy);
}

//TODO - default still at no-referrer
pub fn get_referrer_policy(&self) -> Option<ReferrerPolicy> {
return self.referrer_policy.clone();
return self.referrer_policy.get();
}
}

Expand Down Expand Up @@ -2803,6 +2807,20 @@ fn update_with_current_time_ms(marker: &Cell<u64>) {
}
}

/// https://w3c.github.io/webappsec-referrer-policy/#determine-policy-for-token
pub fn determine_policy_for_token(token: &str) -> Option<ReferrerPolicy> {
let lower = token.to_lowercase();
return match lower.as_ref() {
"never" | "no-referrer" => Some(ReferrerPolicy::NoReferrer),
"default" | "no-referrer-when-downgrade" => Some(ReferrerPolicy::NoRefWhenDowngrade),
"origin" => Some(ReferrerPolicy::OriginOnly),
"origin-when-cross-origin" => Some(ReferrerPolicy::OriginWhenCrossOrigin),
"always" | "unsafe-url" => Some(ReferrerPolicy::UnsafeUrl),
"" => Some(ReferrerPolicy::NoReferrer),
_ => None,
}
}

pub struct DocumentProgressHandler {
addr: Trusted<Document>
}
Expand Down
36 changes: 33 additions & 3 deletions components/script/dom/htmlheadelement.rs
Expand Up @@ -2,13 +2,16 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::HTMLHeadElementBinding;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::Root;
use dom::bindings::js::{Root, RootedReference};
use dom::bindings::str::DOMString;
use dom::document::Document;
use dom::document::{Document, determine_policy_for_token};
use dom::element::Element;
use dom::htmlelement::HTMLElement;
use dom::node::Node;
use dom::htmlmetaelement::HTMLMetaElement;
use dom::node::{Node, document_from_node};
use dom::userscripts::load_script;
use dom::virtualmethods::VirtualMethods;
use string_cache::Atom;
Expand All @@ -34,6 +37,33 @@ impl HTMLHeadElement {
let element = HTMLHeadElement::new_inherited(localName, prefix, document);
Node::reflect_node(box element, document, HTMLHeadElementBinding::Wrap)
}

/// https://html.spec.whatwg.org/multipage/#meta-referrer
pub fn set_document_referrer(&self) {
let doc = document_from_node(self);

if doc.GetHead().r() != Some(self) {
return;
}

let node = self.upcast::<Node>();
let candidates = node.traverse_preorder()
.filter_map(Root::downcast::<Element>)
.filter(|elem| elem.is::<HTMLMetaElement>())
.filter(|elem| elem.get_string_attribute(&atom!("name")) == "referrer")
.filter(|elem| elem.get_attribute(&ns!(), &atom!("content")).is_some());

for meta in candidates {
if let Some(content) = meta.get_attribute(&ns!(), &atom!("content")).r() {
let content = content.value();
let content_val = content.trim();
if !content_val.is_empty() {
doc.set_referrer_policy(determine_policy_for_token(content_val));
return;
}
}
}
}
}

impl VirtualMethods for HTMLHeadElement {
Expand Down
5 changes: 3 additions & 2 deletions components/script/dom/htmliframeelement.rs
Expand Up @@ -144,8 +144,9 @@ impl HTMLIFrameElement {
pub fn process_the_iframe_attributes(&self) {
let url = self.get_url();

// TODO - loaddata here should have referrer info (not None, None)
self.navigate_or_reload_child_browsing_context(Some(LoadData::new(url, None, None)));
let document = document_from_node(self);
self.navigate_or_reload_child_browsing_context(
Some(LoadData::new(url, document.get_referrer_policy(), Some(document.url().clone()))));
}

#[allow(unsafe_code)]
Expand Down
51 changes: 48 additions & 3 deletions components/script/dom/htmlmetaelement.rs
Expand Up @@ -2,17 +2,19 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::attr::AttrValue;
use dom::attr::{Attr, AttrValue};
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::HTMLMetaElementBinding;
use dom::bindings::codegen::Bindings::HTMLMetaElementBinding::HTMLMetaElementMethods;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{Root, RootedReference};
use dom::bindings::str::DOMString;
use dom::document::Document;
use dom::element::Element;
use dom::element::{AttributeMutation, Element};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, document_from_node};
use dom::htmlheadelement::HTMLHeadElement;
use dom::node::{Node, UnbindContext, document_from_node};
use dom::virtualmethods::VirtualMethods;
use std::ascii::AsciiExt;
use std::sync::Arc;
Expand Down Expand Up @@ -59,6 +61,10 @@ impl HTMLMetaElement {
if name == "viewport" {
self.apply_viewport();
}

if name == "referrer" {
self.apply_referrer();
}
}
}

Expand All @@ -85,6 +91,27 @@ impl HTMLMetaElement {
}
}
}

fn process_referrer_attribute(&self) {
let element = self.upcast::<Element>();
if let Some(name) = element.get_attribute(&ns!(), &atom!("name")).r() {
let name = name.value().to_ascii_lowercase();
let name = name.trim_matches(HTML_SPACE_CHARACTERS);

if name == "referrer" {
self.apply_referrer();
}
}
}

/// https://html.spec.whatwg.org/multipage/#meta-referrer
fn apply_referrer(&self) {
if let Some(parent) = self.upcast::<Node>().GetParentElement() {
if let Some(head) = parent.downcast::<HTMLHeadElement>() {
head.set_document_referrer();
}
}
}
}

impl HTMLMetaElementMethods for HTMLMetaElement {
Expand Down Expand Up @@ -122,4 +149,22 @@ impl VirtualMethods for HTMLMetaElement {
_ => self.super_type().unwrap().parse_plain_attribute(name, value),
}
}

fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
if let Some(s) = self.super_type() {
s.attribute_mutated(attr, mutation);
}

self.process_referrer_attribute();
}

fn unbind_from_tree(&self, context: &UnbindContext) {
if let Some(ref s) = self.super_type() {
s.unbind_from_tree(context);
}

if context.tree_in_doc {
self.process_referrer_attribute();
}
}
}
19 changes: 16 additions & 3 deletions components/script/dom/xmlhttprequest.rs
Expand Up @@ -148,10 +148,20 @@ pub struct XMLHttpRequest {
fetch_time: Cell<i64>,
generation_id: Cell<GenerationId>,
response_status: Cell<Result<(), ()>>,
referrer_url: Option<Url>,
referrer_policy: Option<ReferrerPolicy>,
}

impl XMLHttpRequest {
fn new_inherited(global: GlobalRef) -> XMLHttpRequest {
//TODO - update this when referrer policy implemented for workers
let (referrer_url, referrer_policy) = if let GlobalRef::Window(window) = global {
let document = window.Document();
(Some(document.url().clone()), document.get_referrer_policy())
} else {
(None, None)
};

XMLHttpRequest {
eventtarget: XMLHttpRequestEventTarget::new_inherited(),
ready_state: Cell::new(XMLHttpRequestState::Unsent),
Expand Down Expand Up @@ -183,6 +193,8 @@ impl XMLHttpRequest {
fetch_time: Cell::new(0),
generation_id: Cell::new(GenerationId(0)),
response_status: Cell::new(Ok(())),
referrer_url: referrer_url,
referrer_policy: referrer_policy,
}
}
pub fn new(global: GlobalRef) -> Root<XMLHttpRequest> {
Expand Down Expand Up @@ -297,10 +309,10 @@ impl XMLHttpRequest {

impl LoadOrigin for XMLHttpRequest {
fn referrer_url(&self) -> Option<Url> {
None
return self.referrer_url.clone();
}
fn referrer_policy(&self) -> Option<ReferrerPolicy> {
None
return self.referrer_policy;
}
fn request_source(&self) -> RequestSource {
if self.sync.get() {
Expand Down Expand Up @@ -592,11 +604,12 @@ impl XMLHttpRequestMethods for XMLHttpRequest {

// Step 5
let global = self.global();
//TODO - set referrer_policy/referrer_url in load_data

let mut load_data =
LoadData::new(LoadContext::Browsing,
self.request_url.borrow().clone().unwrap(),
self);

if load_data.url.origin().ne(&global.r().get_url().origin()) {
load_data.credentials_flag = self.WithCredentials();
}
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

0 comments on commit 687d0cd

Please sign in to comment.