Rewrite determine_request_referrer() to explicitly limit it to the checks it can do.

Checks for the Client value should reside in the script thread.

I also noted some other issues in this code.
This commit is contained in:
Ms2ger 2016-12-08 11:46:57 -10:00
parent 1e3d4d272d
commit 12aa4694cb
3 changed files with 40 additions and 42 deletions

View file

@ -21,6 +21,7 @@ use net_traits::response::{Response, ResponseBody, ResponseType};
use std::borrow::Cow; use std::borrow::Cow;
use std::fs::File; use std::fs::File;
use std::io::Read; use std::io::Read;
use std::mem;
use std::rc::Rc; use std::rc::Rc;
use std::sync::mpsc::{Sender, Receiver}; use std::sync::mpsc::{Sender, Receiver};
@ -154,15 +155,27 @@ pub fn main_fetch(request: Rc<Request>,
request.referrer_policy.set(Some(referrer_policy)); request.referrer_policy.set(Some(referrer_policy));
// Step 8 // Step 8
if *request.referrer.borrow() != Referrer::NoReferrer { {
// remove Referrer headers set in past redirects/preflights let mut referrer = request.referrer.borrow_mut();
// this stops the assertion in determine_request_referrer from failing let referrer_url = match mem::replace(&mut *referrer, Referrer::NoReferrer) {
request.headers.borrow_mut().remove::<RefererHeader>(); Referrer::NoReferrer => None,
let referrer_url = determine_request_referrer(&mut *request.headers.borrow_mut(), Referrer::Client => {
referrer_policy, // FIXME(#14507): We should never get this value here; it should
request.referrer.borrow_mut().take(), // already have been handled in the script thread.
request.current_url().clone()); request.headers.borrow_mut().remove::<RefererHeader>();
*request.referrer.borrow_mut() = Referrer::from_url(referrer_url); None
},
Referrer::ReferrerUrl(url) => {
request.headers.borrow_mut().remove::<RefererHeader>();
determine_request_referrer(&mut *request.headers.borrow_mut(),
referrer_policy,
url,
request.current_url().clone())
}
};
if let Some(referrer_url) = referrer_url {
*referrer = Referrer::ReferrerUrl(referrer_url);
}
} }
// Step 9 // Step 9

View file

@ -276,27 +276,28 @@ fn strip_url(mut referrer_url: ServoUrl, origin_only: bool) -> Option<ServoUrl>
} }
/// https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer /// https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer
/// Steps 4-6.
pub fn determine_request_referrer(headers: &mut Headers, pub fn determine_request_referrer(headers: &mut Headers,
referrer_policy: ReferrerPolicy, referrer_policy: ReferrerPolicy,
referrer_url: Option<ServoUrl>, referrer_source: ServoUrl,
url: ServoUrl) -> Option<ServoUrl> { current_url: ServoUrl)
//TODO - algorithm step 2 not addressed -> Option<ServoUrl> {
assert!(!headers.has::<Referer>()); assert!(!headers.has::<Referer>());
if let Some(ref_url) = referrer_url { // FIXME(#14505): this does not seem to be the correct way of checking for
let cross_origin = ref_url.origin() != url.origin(); // same-origin requests.
return match referrer_policy { let cross_origin = referrer_source.origin() != current_url.origin();
ReferrerPolicy::NoReferrer => None, // FIXME(#14506): some of these cases are expected to consider whether the
ReferrerPolicy::Origin => strip_url(ref_url, true), // request's client is "TLS-protected", whatever that means.
ReferrerPolicy::SameOrigin => if cross_origin { None } else { strip_url(ref_url, false) }, match referrer_policy {
ReferrerPolicy::UnsafeUrl => strip_url(ref_url, false), ReferrerPolicy::NoReferrer => None,
ReferrerPolicy::OriginWhenCrossOrigin => strip_url(ref_url, cross_origin), ReferrerPolicy::Origin => strip_url(referrer_source, true),
ReferrerPolicy::StrictOrigin => strict_origin(ref_url, url), ReferrerPolicy::SameOrigin => if cross_origin { None } else { strip_url(referrer_source, false) },
ReferrerPolicy::StrictOriginWhenCrossOrigin => strict_origin_when_cross_origin(ref_url, url), ReferrerPolicy::UnsafeUrl => strip_url(referrer_source, false),
ReferrerPolicy::NoReferrerWhenDowngrade => ReferrerPolicy::OriginWhenCrossOrigin => strip_url(referrer_source, cross_origin),
no_referrer_when_downgrade_header(ref_url, url), ReferrerPolicy::StrictOrigin => strict_origin(referrer_source, current_url),
}; ReferrerPolicy::StrictOriginWhenCrossOrigin => strict_origin_when_cross_origin(referrer_source, current_url),
ReferrerPolicy::NoReferrerWhenDowngrade => no_referrer_when_downgrade_header(referrer_source, current_url),
} }
return None;
} }
pub fn set_request_cookies(url: &ServoUrl, headers: &mut Headers, cookie_jar: &Arc<RwLock<CookieStorage>>) { pub fn set_request_cookies(url: &ServoUrl, headers: &mut Headers, cookie_jar: &Arc<RwLock<CookieStorage>>) {

View file

@ -9,7 +9,6 @@ use msg::constellation_msg::PipelineId;
use servo_url::ServoUrl; use servo_url::ServoUrl;
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::default::Default; use std::default::Default;
use std::mem::swap;
use url::{Origin as UrlOrigin}; use url::{Origin as UrlOrigin};
/// An [initiator](https://fetch.spec.whatwg.org/#concept-request-initiator) /// An [initiator](https://fetch.spec.whatwg.org/#concept-request-initiator)
@ -308,19 +307,4 @@ impl Referrer {
Referrer::ReferrerUrl(ref url) => Some(url) Referrer::ReferrerUrl(ref url) => Some(url)
} }
} }
pub fn from_url(url: Option<ServoUrl>) -> Self {
if let Some(url) = url {
Referrer::ReferrerUrl(url)
} else {
Referrer::NoReferrer
}
}
pub fn take(&mut self) -> Option<ServoUrl> {
let mut new = Referrer::Client;
swap(self, &mut new);
match new {
Referrer::NoReferrer | Referrer::Client => None,
Referrer::ReferrerUrl(url) => Some(url)
}
}
} }