mirror of
https://github.com/servo/servo.git
synced 2025-08-02 04:00:32 +01:00
cookies and cookies storage implementation
This commit is contained in:
parent
e14c569ed0
commit
3239aeacdc
13 changed files with 6441 additions and 48 deletions
|
@ -9,3 +9,6 @@ path = "lib.rs"
|
||||||
|
|
||||||
[dependencies.msg]
|
[dependencies.msg]
|
||||||
path = "../msg"
|
path = "../msg"
|
||||||
|
|
||||||
|
[dependencies.util]
|
||||||
|
path = "../util"
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use resource_task::{TargetedLoadResponse, Metadata, LoadData, start_sending, ResponseSenders};
|
use resource_task::{TargetedLoadResponse, Metadata, LoadData, start_sending, ResponseSenders};
|
||||||
|
use resource_task::ControlMsg;
|
||||||
use resource_task::ProgressMsg::Done;
|
use resource_task::ProgressMsg::Done;
|
||||||
use file_loader;
|
use file_loader;
|
||||||
|
|
||||||
|
@ -14,7 +15,7 @@ use std::borrow::ToOwned;
|
||||||
use std::io::fs::PathExtensions;
|
use std::io::fs::PathExtensions;
|
||||||
use std::sync::mpsc::Sender;
|
use std::sync::mpsc::Sender;
|
||||||
|
|
||||||
pub fn factory(mut load_data: LoadData, start_chan: Sender<TargetedLoadResponse>) {
|
pub fn factory(mut load_data: LoadData, start_chan: Sender<TargetedLoadResponse>, cookies_chan: Sender<ControlMsg>) {
|
||||||
let senders = ResponseSenders {
|
let senders = ResponseSenders {
|
||||||
immediate_consumer: start_chan.clone(),
|
immediate_consumer: start_chan.clone(),
|
||||||
eventual_consumer: load_data.consumer.clone(),
|
eventual_consumer: load_data.consumer.clone(),
|
||||||
|
@ -26,8 +27,9 @@ pub fn factory(mut load_data: LoadData, start_chan: Sender<TargetedLoadResponse>
|
||||||
content_type: Some(("text".to_string(), "html".to_string())),
|
content_type: Some(("text".to_string(), "html".to_string())),
|
||||||
charset: Some("utf-8".to_string()),
|
charset: Some("utf-8".to_string()),
|
||||||
headers: None,
|
headers: None,
|
||||||
status: Some(RawStatus(200, "OK".to_owned()))
|
status: Some(RawStatus(200, "OK".to_owned())),
|
||||||
});
|
cookies: Vec::new(),
|
||||||
|
}, cookies_chan);
|
||||||
chan.send(Done(Ok(()))).unwrap();
|
chan.send(Done(Ok(()))).unwrap();
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -39,10 +41,10 @@ pub fn factory(mut load_data: LoadData, start_chan: Sender<TargetedLoadResponse>
|
||||||
load_data.url = Url::from_file_path(&path).unwrap();
|
load_data.url = Url::from_file_path(&path).unwrap();
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
start_sending(senders, Metadata::default(load_data.url))
|
start_sending(senders, Metadata::default(load_data.url), cookies_chan)
|
||||||
.send(Done(Err("Unknown about: URL.".to_string()))).unwrap();
|
.send(Done(Err("Unknown about: URL.".to_string()))).unwrap();
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
file_loader::factory(load_data, start_chan)
|
file_loader::factory(load_data, start_chan, cookies_chan)
|
||||||
}
|
}
|
||||||
|
|
314
components/net/cookie.rs
Normal file
314
components/net/cookie.rs
Normal file
|
@ -0,0 +1,314 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* 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 resource_task::{Metadata, Payload, Done, LoadResponse, LoaderTask, start_sending};
|
||||||
|
//use time::Tm;
|
||||||
|
use url::Url;
|
||||||
|
use std::ascii::AsciiExt;
|
||||||
|
use time::{strptime, Tm, at, get_time, Timespec, now};
|
||||||
|
use std::i64;
|
||||||
|
use pub_domains::PUB_DOMAINS;
|
||||||
|
use std::io::net::ip::IpAddr;
|
||||||
|
|
||||||
|
#[derive(Clone, Show)]
|
||||||
|
pub struct Cookie {
|
||||||
|
pub name: String,
|
||||||
|
pub value: String,
|
||||||
|
pub domain: String,
|
||||||
|
pub expires: Option<Tm>,
|
||||||
|
pub path: String,
|
||||||
|
pub secure: bool,
|
||||||
|
pub http_only: bool,
|
||||||
|
pub host_only: bool,
|
||||||
|
pub persistent: bool,
|
||||||
|
pub created_at: Tm,
|
||||||
|
pub last_access: Tm,
|
||||||
|
pub scheme: String
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Cookie {
|
||||||
|
pub fn new(header_value: String, url: &Url) -> Option<Cookie> {
|
||||||
|
let mut secure = false;
|
||||||
|
let mut http_only = false;
|
||||||
|
let mut name = None;
|
||||||
|
let mut value = None;
|
||||||
|
let mut domain = "".to_string();
|
||||||
|
let mut path = "".to_string();
|
||||||
|
let mut expires = None;
|
||||||
|
let mut max_age = None;
|
||||||
|
|
||||||
|
let mut set_cookie_iter = header_value.as_slice().split(';');
|
||||||
|
match set_cookie_iter.next() {
|
||||||
|
Some(name_value_pair) => {
|
||||||
|
if !name_value_pair.contains_char('=') {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let mut data = name_value_pair.split('=').map(|x| x.trim());
|
||||||
|
name = data.next();
|
||||||
|
value = data.next();
|
||||||
|
}
|
||||||
|
None => { return None }
|
||||||
|
}
|
||||||
|
|
||||||
|
if name.is_some() && name.unwrap() == "" {
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
|
||||||
|
for spl in set_cookie_iter {
|
||||||
|
let cookie_av = spl.trim();
|
||||||
|
if cookie_av.contains_char('=') {
|
||||||
|
match cookie_av.split('=').map(|x| x.trim()).collect::<Vec<&str>>().as_slice() {
|
||||||
|
[attr, val] if attr.eq_ignore_ascii_case("domain") => {
|
||||||
|
if val == "" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let cookie_domain;
|
||||||
|
if val.char_at(0) == '.' {
|
||||||
|
cookie_domain = val.slice_from(1);
|
||||||
|
} else {
|
||||||
|
cookie_domain = val;
|
||||||
|
}
|
||||||
|
domain = cookie_domain.to_ascii_lowercase();
|
||||||
|
}
|
||||||
|
[attr, val] if attr.eq_ignore_ascii_case("path") => {
|
||||||
|
if val == "" || val.char_at(0) != '/' {
|
||||||
|
match url.path() {
|
||||||
|
Some(x) => {
|
||||||
|
let mut url_path = "".to_string();
|
||||||
|
for v in x.iter() {
|
||||||
|
url_path.push_str(v.as_slice())
|
||||||
|
}
|
||||||
|
path = Cookie::default_path(url_path.as_slice())
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
path = val.to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
[attr, val] if attr.eq_ignore_ascii_case("expires") => {
|
||||||
|
// we try strptime with three date formats according to
|
||||||
|
// http://tools.ietf.org/html/rfc2616#section-3.3.1
|
||||||
|
match strptime(val, "%a, %d %b %Y %H:%M:%S %Z") {
|
||||||
|
Ok(x) => expires = Some(x),
|
||||||
|
Err(_) => {
|
||||||
|
match strptime(val, "%A, %d-%b-%y %H:%M:%S %Z") {
|
||||||
|
Ok(x) => expires = Some(x),
|
||||||
|
Err(_) => {
|
||||||
|
match strptime(val, "%a %b %d %H:%M:%S %Y") {
|
||||||
|
Ok(x) => expires = Some(x),
|
||||||
|
Err(_) => continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[attr, val] if attr.eq_ignore_ascii_case("max-age") => {
|
||||||
|
match val.parse() {
|
||||||
|
Some(x) if x > 0 => {
|
||||||
|
let mut expires = get_time();
|
||||||
|
expires.sec += x;
|
||||||
|
max_age = Some(at(expires));
|
||||||
|
}
|
||||||
|
Some(_) => {
|
||||||
|
max_age = Some(at(Timespec::new(0, 0)))
|
||||||
|
}
|
||||||
|
None => continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x => { println!("Undefined cookie attr value: {:?}", x); }
|
||||||
|
}
|
||||||
|
} else if cookie_av.eq_ignore_ascii_case("secure") {
|
||||||
|
secure = true;
|
||||||
|
} else if cookie_av.eq_ignore_ascii_case("httponly") {
|
||||||
|
http_only = true;
|
||||||
|
} else {
|
||||||
|
println!("Undefined cookie attr value: {}", cookie_av)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let url_host = match url.host() {
|
||||||
|
Some(x) => x.serialize(),
|
||||||
|
None => "".to_string()
|
||||||
|
};
|
||||||
|
let mut cookie = Cookie {
|
||||||
|
name: name.unwrap().to_string(),
|
||||||
|
value: value.unwrap().to_string(),
|
||||||
|
created_at: now(),
|
||||||
|
last_access: now(),
|
||||||
|
domain: url_host.clone(),
|
||||||
|
expires: None,
|
||||||
|
path: path,
|
||||||
|
secure: secure,
|
||||||
|
http_only: http_only,
|
||||||
|
host_only: true,
|
||||||
|
persistent: false,
|
||||||
|
scheme: url.scheme.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
if max_age.is_some() {
|
||||||
|
cookie.persistent = true;
|
||||||
|
cookie.expires = max_age;
|
||||||
|
} else if expires.is_some() {
|
||||||
|
cookie.persistent = true;
|
||||||
|
cookie.expires = expires;
|
||||||
|
} else {
|
||||||
|
cookie.expires = Some(at(Timespec::new(i64::MAX, 0)))
|
||||||
|
}
|
||||||
|
|
||||||
|
match PUB_DOMAINS.iter().find(|&x| domain == *x) {
|
||||||
|
Some(val) if *val == url_host => domain = "".to_string(),
|
||||||
|
Some(_) => return None,
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
if !domain.is_empty() {
|
||||||
|
if !Cookie::domain_match(url_host.as_slice(), domain.as_slice()) {
|
||||||
|
return None;
|
||||||
|
} else {
|
||||||
|
cookie.host_only = false;
|
||||||
|
cookie.domain = domain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cookie.http_only && !url.scheme.as_slice().starts_with("http") {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(cookie)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn touch(&mut self) {
|
||||||
|
self.last_access = now();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_path(request_path: &str) -> String {
|
||||||
|
if request_path == "" || request_path.char_at(0) != '/' || request_path == "/" {
|
||||||
|
return "/".to_string();
|
||||||
|
}
|
||||||
|
if request_path.ends_with("/") {
|
||||||
|
return request_path.slice_to(request_path.len()-1).to_string();
|
||||||
|
}
|
||||||
|
return request_path.clone().to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn path_match(request_path: &str, cookie_path: &str) -> bool {
|
||||||
|
request_path == cookie_path ||
|
||||||
|
( request_path.starts_with(cookie_path) &&
|
||||||
|
( request_path.ends_with("/") || request_path.char_at(cookie_path.len()) == '/' )
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn domain_match(string: &str, domain_string: &str) -> bool {
|
||||||
|
if string == domain_string {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if string.ends_with(domain_string)
|
||||||
|
&& string.char_at(string.len()-domain_string.len()-1) == '.'
|
||||||
|
&& string.parse::<IpAddr>().is_none() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn appropriate_for_url(&self, url: Url) -> bool {
|
||||||
|
let domain = url.host().unwrap().serialize();
|
||||||
|
let mut result = if self.host_only {
|
||||||
|
self.domain == domain
|
||||||
|
} else {
|
||||||
|
Cookie::domain_match(domain.as_slice(), self.domain.as_slice())
|
||||||
|
};
|
||||||
|
result = result && Cookie::path_match(url.serialize_path().unwrap().as_slice(), self.path.as_slice());
|
||||||
|
|
||||||
|
if self.secure {
|
||||||
|
result = result && url.scheme == "https".to_string()
|
||||||
|
}
|
||||||
|
if self.http_only {
|
||||||
|
result = result && url.scheme.as_slice().starts_with("http")
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_domain_match() {
|
||||||
|
assert!(Cookie::domain_match("foo.com", "foo.com"));
|
||||||
|
assert!(Cookie::domain_match("bar.foo.com", "foo.com"));
|
||||||
|
assert!(Cookie::domain_match("baz.bar.foo.com", "foo.com"));
|
||||||
|
|
||||||
|
assert!(!Cookie::domain_match("bar.foo.com", "bar.com"));
|
||||||
|
assert!(!Cookie::domain_match("bar.com", "baz.bar.com"));
|
||||||
|
assert!(!Cookie::domain_match("foo.com", "bar.com"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_default_path() {
|
||||||
|
assert!(Cookie::default_path("/foo/bar/baz/").as_slice() == "/foo/bar/baz");
|
||||||
|
assert!(Cookie::default_path("/foo").as_slice() == "/foo");
|
||||||
|
assert!(Cookie::default_path("/").as_slice() == "/");
|
||||||
|
assert!(Cookie::default_path("").as_slice() == "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fn_cookie_constructor() {
|
||||||
|
let url = &Url::parse("http://example.com/foo").unwrap();
|
||||||
|
|
||||||
|
let gov_url = &Url::parse("http://gov.ac/foo").unwrap();
|
||||||
|
// cookie name/value test
|
||||||
|
assert!(Cookie::new(" baz ".to_string(), url).is_none());
|
||||||
|
assert!(Cookie::new(" = bar ".to_string(), url).is_none());
|
||||||
|
assert!(Cookie::new(" baz = ".to_string(), url).is_some());
|
||||||
|
|
||||||
|
// cookie domains test
|
||||||
|
assert!(Cookie::new(" baz = bar; Domain = ".to_string(), url).is_some());
|
||||||
|
assert!(Cookie::new(" baz = bar; Domain = ".to_string(), url).unwrap().domain.as_slice() == "example.com");
|
||||||
|
|
||||||
|
// cookie public domains test
|
||||||
|
assert!(Cookie::new(" baz = bar; Domain = gov.ac".to_string(), url).is_none());
|
||||||
|
assert!(Cookie::new(" baz = bar; Domain = gov.ac".to_string(), gov_url).is_some());
|
||||||
|
|
||||||
|
// cookie domain matching test
|
||||||
|
assert!(Cookie::new(" baz = bar ; Secure; Domain = bazample.com".to_string(), url).is_none());
|
||||||
|
|
||||||
|
assert!(Cookie::new(" baz = bar ; Secure; Path = /foo/bar/".to_string(), url).is_some());
|
||||||
|
|
||||||
|
let cookie = Cookie::new(" baz = bar ; Secure; Path = /foo/bar/".to_string(), url).unwrap();
|
||||||
|
assert!(cookie.value.as_slice() == "bar");
|
||||||
|
assert!(cookie.name.as_slice() == "baz");
|
||||||
|
assert!(cookie.secure);
|
||||||
|
assert!(cookie.path.as_slice() == "/foo/bar/");
|
||||||
|
assert!(cookie.domain.as_slice() == "example.com");
|
||||||
|
assert!(cookie.host_only);
|
||||||
|
|
||||||
|
let u = &Url::parse("http://example.com/foobar").unwrap();
|
||||||
|
assert!(Cookie::new("foobar=value;path=/".to_string(), u).is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deriving(Clone)]
|
||||||
|
pub struct CookieManager {
|
||||||
|
cookies: Vec<Cookie>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CookieManager {
|
||||||
|
pub fn new() -> CookieManager {
|
||||||
|
CookieManager {
|
||||||
|
cookies: Vec::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add(&mut self, cookie: &Cookie) -> bool {
|
||||||
|
match self.cookies.iter().find(|x| x.domain == cookie.domain && x.name == cookie.name && x.path == cookie.path) {
|
||||||
|
Some(c) => {
|
||||||
|
if c.http_only && !cookie.scheme.as_slice().starts_with("http") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
self.cookies.push(cookie.clone());
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
46
components/net/cookie_storage.rs
Normal file
46
components/net/cookie_storage.rs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
use url::Url;
|
||||||
|
use cookie::Cookie;
|
||||||
|
|
||||||
|
pub struct CookieStorage {
|
||||||
|
cookies: Vec<Cookie>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CookieStorage {
|
||||||
|
pub fn new() -> CookieStorage {
|
||||||
|
CookieStorage {
|
||||||
|
cookies: Vec::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, cookie: Cookie) {
|
||||||
|
match self.cookies.iter().position(|c| c.domain == cookie.domain && c.path == cookie.path && c.name == cookie.name) {
|
||||||
|
Some(ind) => { self.cookies.remove(ind); }
|
||||||
|
None => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.cookies.push(cookie);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cookies_for_url(&mut self, url: Url) -> Option<String> {
|
||||||
|
let filterer = |&:c: &&mut Cookie| -> bool {
|
||||||
|
error!(" === SENT COOKIE : {} {} {} {}", c.name, c.value, c.domain, c.path);
|
||||||
|
error!(" === SENT COOKIE RESULT {}", c.appropriate_for_url(url.clone()));
|
||||||
|
c.appropriate_for_url(url.clone())
|
||||||
|
};
|
||||||
|
let mut url_cookies = self.cookies.iter_mut().filter(filterer);
|
||||||
|
let reducer = |&:acc: String, c: &mut Cookie| -> String {
|
||||||
|
c.touch();
|
||||||
|
(match acc.len() {
|
||||||
|
0 => acc,
|
||||||
|
_ => acc + ";"
|
||||||
|
}) + c.name.as_slice() + "=" + c.value.as_slice()
|
||||||
|
};
|
||||||
|
let result = url_cookies.fold("".to_string(), reducer);
|
||||||
|
|
||||||
|
error!(" === COOKIES SENT: {}", result);
|
||||||
|
match result.len() {
|
||||||
|
0 => None,
|
||||||
|
_ => Some(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use resource_task::{Metadata, LoadData, TargetedLoadResponse, start_sending, ResponseSenders};
|
use resource_task::{Metadata, LoadData, TargetedLoadResponse, start_sending, ResponseSenders};
|
||||||
|
use resource_task::ControlMsg;
|
||||||
use resource_task::ProgressMsg::{Payload, Done};
|
use resource_task::ProgressMsg::{Payload, Done};
|
||||||
|
|
||||||
use serialize::base64::FromBase64;
|
use serialize::base64::FromBase64;
|
||||||
|
@ -12,15 +13,15 @@ use url::{percent_decode, SchemeData};
|
||||||
|
|
||||||
use std::sync::mpsc::Sender;
|
use std::sync::mpsc::Sender;
|
||||||
|
|
||||||
pub fn factory(load_data: LoadData, start_chan: Sender<TargetedLoadResponse>) {
|
pub fn factory(load_data: LoadData, start_chan: Sender<TargetedLoadResponse>, cookies_chan: Sender<ControlMsg>) {
|
||||||
// NB: we don't spawn a new task.
|
// NB: we don't spawn a new task.
|
||||||
// Hypothesis: data URLs are too small for parallel base64 etc. to be worth it.
|
// Hypothesis: data URLs are too small for parallel base64 etc. to be worth it.
|
||||||
// Should be tested at some point.
|
// Should be tested at some point.
|
||||||
// Left in separate function to allow easy moving to a task, if desired.
|
// Left in separate function to allow easy moving to a task, if desired.
|
||||||
load(load_data, start_chan)
|
load(load_data, start_chan, cookies_chan)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load(load_data: LoadData, start_chan: Sender<TargetedLoadResponse>) {
|
fn load(load_data: LoadData, start_chan: Sender<TargetedLoadResponse>, cookies_chan: Sender<ControlMsg>) {
|
||||||
let url = load_data.url;
|
let url = load_data.url;
|
||||||
assert!("data" == url.scheme.as_slice());
|
assert!("data" == url.scheme.as_slice());
|
||||||
|
|
||||||
|
@ -45,7 +46,7 @@ fn load(load_data: LoadData, start_chan: Sender<TargetedLoadResponse>) {
|
||||||
}
|
}
|
||||||
let parts: Vec<&str> = scheme_data.as_slice().splitn(1, ',').collect();
|
let parts: Vec<&str> = scheme_data.as_slice().splitn(1, ',').collect();
|
||||||
if parts.len() != 2 {
|
if parts.len() != 2 {
|
||||||
start_sending(senders, metadata).send(Done(Err("invalid data uri".to_string()))).unwrap();
|
start_sending(senders, metadata, cookies_chan).send(Done(Err("invalid data uri".to_string()))).unwrap();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +64,7 @@ fn load(load_data: LoadData, start_chan: Sender<TargetedLoadResponse>) {
|
||||||
let content_type: Option<Mime> = ct_str.parse();
|
let content_type: Option<Mime> = ct_str.parse();
|
||||||
metadata.set_content_type(content_type.as_ref());
|
metadata.set_content_type(content_type.as_ref());
|
||||||
|
|
||||||
let progress_chan = start_sending(senders, metadata);
|
let progress_chan = start_sending(senders, metadata, cookies_chan);
|
||||||
let bytes = percent_decode(parts[1].as_bytes());
|
let bytes = percent_decode(parts[1].as_bytes());
|
||||||
|
|
||||||
if is_base64 {
|
if is_base64 {
|
||||||
|
@ -95,8 +96,9 @@ fn assert_parse(url: &'static str,
|
||||||
use sniffer_task;
|
use sniffer_task;
|
||||||
|
|
||||||
let (start_chan, start_port) = channel();
|
let (start_chan, start_port) = channel();
|
||||||
|
let (cookies_chan, _) = channel();
|
||||||
let sniffer_task = sniffer_task::new_sniffer_task();
|
let sniffer_task = sniffer_task::new_sniffer_task();
|
||||||
load(LoadData::new(Url::parse(url).unwrap(), start_chan), sniffer_task);
|
load(LoadData::new(Url::parse(url).unwrap(), start_chan), sniffer_task, cookies_chan);
|
||||||
|
|
||||||
let response = start_port.recv().unwrap();
|
let response = start_port.recv().unwrap();
|
||||||
assert_eq!(&response.metadata.content_type, &content_type);
|
assert_eq!(&response.metadata.content_type, &content_type);
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use resource_task::{ProgressMsg, Metadata, LoadData, start_sending, TargetedLoadResponse, ResponseSenders};
|
use resource_task::{ProgressMsg, Metadata, LoadData, start_sending, TargetedLoadResponse, ResponseSenders};
|
||||||
|
use resource_task::ControlMsg;
|
||||||
use resource_task::ProgressMsg::{Payload, Done};
|
use resource_task::ProgressMsg::{Payload, Done};
|
||||||
|
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::ToOwned;
|
||||||
|
@ -32,14 +33,14 @@ fn read_all(reader: &mut io::Stream, progress_chan: &Sender<ProgressMsg>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn factory(load_data: LoadData, start_chan: Sender<TargetedLoadResponse>) {
|
pub fn factory(load_data: LoadData, start_chan: Sender<TargetedLoadResponse>, cookies_chan: Sender<ControlMsg>) {
|
||||||
let url = load_data.url;
|
let url = load_data.url;
|
||||||
assert!("file" == url.scheme.as_slice());
|
assert!("file" == url.scheme.as_slice());
|
||||||
let senders = ResponseSenders {
|
let senders = ResponseSenders {
|
||||||
immediate_consumer: start_chan,
|
immediate_consumer: start_chan,
|
||||||
eventual_consumer: load_data.consumer,
|
eventual_consumer: load_data.consumer,
|
||||||
};
|
};
|
||||||
let progress_chan = start_sending(senders, Metadata::default(url.clone()));
|
let progress_chan = start_sending(senders, Metadata::default(url.clone()), cookies_chan);
|
||||||
spawn_named("file_loader".to_owned(), move || {
|
spawn_named("file_loader".to_owned(), move || {
|
||||||
let file_path: Result<Path, ()> = url.to_file_path();
|
let file_path: Result<Path, ()> = url.to_file_path();
|
||||||
match file_path {
|
match file_path {
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use cookie::Cookie;
|
||||||
use resource_task::{Metadata, TargetedLoadResponse, LoadData, start_sending_opt, ResponseSenders};
|
use resource_task::{Metadata, TargetedLoadResponse, LoadData, start_sending_opt, ResponseSenders};
|
||||||
|
use resource_task::ControlMsg;
|
||||||
use resource_task::ProgressMsg::{Payload, Done};
|
use resource_task::ProgressMsg::{Payload, Done};
|
||||||
|
|
||||||
use log;
|
use log;
|
||||||
|
@ -24,21 +26,21 @@ use url::{Url, UrlParser};
|
||||||
|
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::ToOwned;
|
||||||
|
|
||||||
pub fn factory(load_data: LoadData, start_chan: Sender<TargetedLoadResponse>) {
|
pub fn factory(load_data: LoadData, start_chan: Sender<TargetedLoadResponse>, cookies_chan: Sender<ControlMsg>) {
|
||||||
spawn_named("http_loader".to_owned(), move || load(load_data, start_chan))
|
spawn_named("http_loader".to_owned(), move || load(load_data, start_chan, cookies_chan))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_error(url: Url, err: String, senders: ResponseSenders) {
|
fn send_error(url: Url, err: String, senders: ResponseSenders, cookies_chan: Sender<ControlMsg>) {
|
||||||
let mut metadata = Metadata::default(url);
|
let mut metadata = Metadata::default(url);
|
||||||
metadata.status = None;
|
metadata.status = None;
|
||||||
|
|
||||||
match start_sending_opt(senders, metadata) {
|
match start_sending_opt(senders, metadata, cookies_chan) {
|
||||||
Ok(p) => p.send(Done(Err(err))).unwrap(),
|
Ok(p) => p.send(Done(Err(err))).unwrap(),
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load(load_data: LoadData, start_chan: Sender<TargetedLoadResponse>) {
|
fn load(load_data: LoadData, start_chan: Sender<TargetedLoadResponse>, cookies_chan: Sender<ControlMsg>) {
|
||||||
// FIXME: At the time of writing this FIXME, servo didn't have any central
|
// FIXME: At the time of writing this FIXME, servo didn't have any central
|
||||||
// location for configuration. If you're reading this and such a
|
// location for configuration. If you're reading this and such a
|
||||||
// repository DOES exist, please update this constant to use it.
|
// repository DOES exist, please update this constant to use it.
|
||||||
|
@ -57,12 +59,12 @@ fn load(load_data: LoadData, start_chan: Sender<TargetedLoadResponse>) {
|
||||||
iters = iters + 1;
|
iters = iters + 1;
|
||||||
|
|
||||||
if iters > max_redirects {
|
if iters > max_redirects {
|
||||||
send_error(url, "too many redirects".to_string(), senders);
|
send_error(url, "too many redirects".to_string(), senders, cookies_chan);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if redirected_to.contains(&url) {
|
if redirected_to.contains(&url) {
|
||||||
send_error(url, "redirect loop".to_string(), senders);
|
send_error(url, "redirect loop".to_string(), senders, cookies_chan);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +74,7 @@ fn load(load_data: LoadData, start_chan: Sender<TargetedLoadResponse>) {
|
||||||
"http" | "https" => {}
|
"http" | "https" => {}
|
||||||
_ => {
|
_ => {
|
||||||
let s = format!("{} request, but we don't support that scheme", url.scheme);
|
let s = format!("{} request, but we don't support that scheme", url.scheme);
|
||||||
send_error(url, s, senders);
|
send_error(url, s, senders, cookies_chan);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,7 +106,7 @@ reason: \"certificate verify failed\" }]";
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("{:?}", e);
|
println!("{:?}", e);
|
||||||
send_error(url, e.description().to_string(), senders);
|
send_error(url, e.description().to_string(), senders, cookies_chan);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -124,13 +126,13 @@ reason: \"certificate verify failed\" }]";
|
||||||
let mut writer = match req.start() {
|
let mut writer = match req.start() {
|
||||||
Ok(w) => w,
|
Ok(w) => w,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
send_error(url, e.description().to_string(), senders);
|
send_error(url, e.description().to_string(), senders, cookies_chan);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
match writer.write(data.as_slice()) {
|
match writer.write(data.as_slice()) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
send_error(url, e.desc.to_string(), senders);
|
send_error(url, e.desc.to_string(), senders, cookies_chan);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -145,7 +147,7 @@ reason: \"certificate verify failed\" }]";
|
||||||
match req.start() {
|
match req.start() {
|
||||||
Ok(w) => w,
|
Ok(w) => w,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
send_error(url, e.description().to_string(), senders);
|
send_error(url, e.description().to_string(), senders, cookies_chan);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,7 +156,7 @@ reason: \"certificate verify failed\" }]";
|
||||||
let mut response = match writer.send() {
|
let mut response = match writer.send() {
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
send_error(url, e.description().to_string(), senders);
|
send_error(url, e.description().to_string(), senders, cookies_chan);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -167,6 +169,16 @@ reason: \"certificate verify failed\" }]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut cookies = Vec::new();
|
||||||
|
for header in response.headers.iter() {
|
||||||
|
if header.name().as_slice() == "Set-Cookie" {
|
||||||
|
match Cookie::new(header.value_string(), &url) {
|
||||||
|
Some(cookie) => cookies.push(cookie),
|
||||||
|
None => continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if response.status.class() == StatusClass::Redirection {
|
if response.status.class() == StatusClass::Redirection {
|
||||||
match response.headers.get::<Location>() {
|
match response.headers.get::<Location>() {
|
||||||
Some(&Location(ref new_url)) => {
|
Some(&Location(ref new_url)) => {
|
||||||
|
@ -175,7 +187,7 @@ reason: \"certificate verify failed\" }]";
|
||||||
Some(ref c) => {
|
Some(ref c) => {
|
||||||
if c.preflight {
|
if c.preflight {
|
||||||
// The preflight lied
|
// The preflight lied
|
||||||
send_error(url, "Preflight fetch inconsistent with main fetch".to_string(), senders);
|
send_error(url, "Preflight fetch inconsistent with main fetch".to_string(), senders, cookies_chan);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
// XXXManishearth There are some CORS-related steps here,
|
// XXXManishearth There are some CORS-related steps here,
|
||||||
|
@ -187,7 +199,7 @@ reason: \"certificate verify failed\" }]";
|
||||||
let new_url = match UrlParser::new().base_url(&url).parse(new_url.as_slice()) {
|
let new_url = match UrlParser::new().base_url(&url).parse(new_url.as_slice()) {
|
||||||
Ok(u) => u,
|
Ok(u) => u,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
send_error(url, e.to_string(), senders);
|
send_error(url, e.to_string(), senders, cookies_chan);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -206,8 +218,9 @@ reason: \"certificate verify failed\" }]";
|
||||||
});
|
});
|
||||||
metadata.headers = Some(response.headers.clone());
|
metadata.headers = Some(response.headers.clone());
|
||||||
metadata.status = Some(response.status_raw().clone());
|
metadata.status = Some(response.status_raw().clone());
|
||||||
|
metadata.cookies = cookies;
|
||||||
|
|
||||||
let progress_chan = match start_sending_opt(senders, metadata) {
|
let progress_chan = match start_sending_opt(senders, metadata, cookies_chan) {
|
||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
_ => return
|
_ => return
|
||||||
};
|
};
|
||||||
|
|
|
@ -555,6 +555,13 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mock_resource_task<T: Closure+Send>(on_load: Box<T>) -> ResourceTask {
|
fn mock_resource_task<T: Closure+Send>(on_load: Box<T>) -> ResourceTask {
|
||||||
|
let cookie_chan = spawn_listener(move |port: Receiver<resource_task::ControlMsg>| {
|
||||||
|
loop {
|
||||||
|
match port.recv() {
|
||||||
|
_ => { continue }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
spawn_listener(move |port: Receiver<resource_task::ControlMsg>| {
|
spawn_listener(move |port: Receiver<resource_task::ControlMsg>| {
|
||||||
loop {
|
loop {
|
||||||
match port.recv().unwrap() {
|
match port.recv().unwrap() {
|
||||||
|
@ -565,9 +572,10 @@ mod tests {
|
||||||
eventual_consumer: response.consumer.clone(),
|
eventual_consumer: response.consumer.clone(),
|
||||||
};
|
};
|
||||||
let chan = start_sending(senders, Metadata::default(
|
let chan = start_sending(senders, Metadata::default(
|
||||||
Url::parse("file:///fake").unwrap()));
|
Url::parse("file:///fake", cookie_chan.clone()).unwrap()));
|
||||||
on_load.invoke(chan);
|
on_load.invoke(chan);
|
||||||
}
|
}
|
||||||
|
resource_task::ControlMsg::Cookies(_) => {}
|
||||||
resource_task::ControlMsg::Exit => break
|
resource_task::ControlMsg::Exit => break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -710,6 +718,13 @@ mod tests {
|
||||||
let (image_bin_sent_chan, image_bin_sent) = channel();
|
let (image_bin_sent_chan, image_bin_sent) = channel();
|
||||||
|
|
||||||
let (resource_task_exited_chan, resource_task_exited) = channel();
|
let (resource_task_exited_chan, resource_task_exited) = channel();
|
||||||
|
let cookie_chan = spawn_listener(move |port: Receiver<resource_task::ControlMsg>| {
|
||||||
|
loop {
|
||||||
|
match port.recv() {
|
||||||
|
_ => { continue }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let mock_resource_task = spawn_listener(move |port: Receiver<resource_task::ControlMsg>| {
|
let mock_resource_task = spawn_listener(move |port: Receiver<resource_task::ControlMsg>| {
|
||||||
loop {
|
loop {
|
||||||
|
@ -721,11 +736,12 @@ mod tests {
|
||||||
eventual_consumer: response.consumer.clone(),
|
eventual_consumer: response.consumer.clone(),
|
||||||
};
|
};
|
||||||
let chan = start_sending(senders, Metadata::default(
|
let chan = start_sending(senders, Metadata::default(
|
||||||
Url::parse("file:///fake").unwrap()));
|
Url::parse("file:///fake").unwrap()), cookie_chan.clone());
|
||||||
chan.send(Payload(test_image_bin()));
|
chan.send(Payload(test_image_bin()));
|
||||||
chan.send(Done(Ok(())));
|
chan.send(Done(Ok(())));
|
||||||
image_bin_sent_chan.send(());
|
image_bin_sent_chan.send(());
|
||||||
}
|
}
|
||||||
|
resource_task::ControlMsg::Cookies(_) => {}
|
||||||
resource_task::ControlMsg::Exit => {
|
resource_task::ControlMsg::Exit => {
|
||||||
resource_task_exited_chan.send(());
|
resource_task_exited_chan.send(());
|
||||||
break
|
break
|
||||||
|
@ -762,7 +778,13 @@ mod tests {
|
||||||
let (image_bin_sent_chan, image_bin_sent) = channel();
|
let (image_bin_sent_chan, image_bin_sent) = channel();
|
||||||
|
|
||||||
let (resource_task_exited_chan, resource_task_exited) = channel();
|
let (resource_task_exited_chan, resource_task_exited) = channel();
|
||||||
|
let cookie_chan = spawn_listener(move |port: Receiver<resource_task::ControlMsg>| {
|
||||||
|
loop {
|
||||||
|
match port.recv() {
|
||||||
|
_ => { continue }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
let mock_resource_task = spawn_listener(move |port: Receiver<resource_task::ControlMsg>| {
|
let mock_resource_task = spawn_listener(move |port: Receiver<resource_task::ControlMsg>| {
|
||||||
loop {
|
loop {
|
||||||
match port.recv().unwrap() {
|
match port.recv().unwrap() {
|
||||||
|
@ -773,11 +795,12 @@ mod tests {
|
||||||
eventual_consumer: response.consumer.clone(),
|
eventual_consumer: response.consumer.clone(),
|
||||||
};
|
};
|
||||||
let chan = start_sending(senders, Metadata::default(
|
let chan = start_sending(senders, Metadata::default(
|
||||||
Url::parse("file:///fake").unwrap()));
|
Url::parse("file:///fake").unwrap()), cookie_chan.clone());
|
||||||
chan.send(Payload(test_image_bin()));
|
chan.send(Payload(test_image_bin()));
|
||||||
chan.send(Done(Err("".to_string())));
|
chan.send(Done(Err("".to_string())));
|
||||||
image_bin_sent_chan.send(());
|
image_bin_sent_chan.send(());
|
||||||
}
|
}
|
||||||
|
resource_task::ControlMsg::Cookies(_) => {}
|
||||||
resource_task::ControlMsg::Exit => {
|
resource_task::ControlMsg::Exit => {
|
||||||
resource_task_exited_chan.send(());
|
resource_task_exited_chan.send(());
|
||||||
break
|
break
|
||||||
|
|
|
@ -38,8 +38,11 @@ pub mod about_loader;
|
||||||
pub mod file_loader;
|
pub mod file_loader;
|
||||||
pub mod http_loader;
|
pub mod http_loader;
|
||||||
pub mod data_loader;
|
pub mod data_loader;
|
||||||
|
pub mod cookie;
|
||||||
|
pub mod cookie_storage;
|
||||||
pub mod image_cache_task;
|
pub mod image_cache_task;
|
||||||
pub mod local_image_cache;
|
pub mod local_image_cache;
|
||||||
|
pub mod pub_domains;
|
||||||
pub mod resource_task;
|
pub mod resource_task;
|
||||||
pub mod storage_task;
|
pub mod storage_task;
|
||||||
mod sniffer_task;
|
mod sniffer_task;
|
||||||
|
|
5959
components/net/pub_domains.rs
Normal file
5959
components/net/pub_domains.rs
Normal file
File diff suppressed because it is too large
Load diff
|
@ -10,6 +10,8 @@ use file_loader;
|
||||||
use http_loader;
|
use http_loader;
|
||||||
use sniffer_task;
|
use sniffer_task;
|
||||||
use sniffer_task::SnifferTask;
|
use sniffer_task::SnifferTask;
|
||||||
|
use cookie::Cookie;
|
||||||
|
use cookie_storage::CookieStorage;
|
||||||
|
|
||||||
use util::task::spawn_named;
|
use util::task::spawn_named;
|
||||||
|
|
||||||
|
@ -26,6 +28,7 @@ use std::sync::mpsc::{channel, Receiver, Sender};
|
||||||
pub enum ControlMsg {
|
pub enum ControlMsg {
|
||||||
/// Request the data associated with a particular URL
|
/// Request the data associated with a particular URL
|
||||||
Load(LoadData),
|
Load(LoadData),
|
||||||
|
Cookies(Vec<Cookie>),
|
||||||
Exit
|
Exit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +64,7 @@ pub struct ResourceCORSData {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Metadata about a loaded resource, such as is obtained from HTTP headers.
|
/// Metadata about a loaded resource, such as is obtained from HTTP headers.
|
||||||
|
#[deriving(Clone)]
|
||||||
pub struct Metadata {
|
pub struct Metadata {
|
||||||
/// Final URL after redirects.
|
/// Final URL after redirects.
|
||||||
pub final_url: Url,
|
pub final_url: Url,
|
||||||
|
@ -75,7 +79,9 @@ pub struct Metadata {
|
||||||
pub headers: Option<Headers>,
|
pub headers: Option<Headers>,
|
||||||
|
|
||||||
/// HTTP Status
|
/// HTTP Status
|
||||||
pub status: Option<RawStatus>
|
pub status: Option<RawStatus>,
|
||||||
|
|
||||||
|
pub cookies: Vec<Cookie>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Metadata {
|
impl Metadata {
|
||||||
|
@ -87,7 +93,8 @@ impl Metadata {
|
||||||
charset: None,
|
charset: None,
|
||||||
headers: None,
|
headers: None,
|
||||||
// http://fetch.spec.whatwg.org/#concept-response-status-message
|
// http://fetch.spec.whatwg.org/#concept-response-status-message
|
||||||
status: Some(RawStatus(200, "OK".to_owned()))
|
status: Some(RawStatus(200, "OK".to_owned())),
|
||||||
|
cookies: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,13 +147,14 @@ pub enum ProgressMsg {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For use by loaders in responding to a Load message.
|
/// For use by loaders in responding to a Load message.
|
||||||
pub fn start_sending(senders: ResponseSenders, metadata: Metadata) -> Sender<ProgressMsg> {
|
pub fn start_sending(senders: ResponseSenders, metadata: Metadata, cookies_chan: Sender<ControlMsg>) -> Sender<ProgressMsg> {
|
||||||
start_sending_opt(senders, metadata).ok().unwrap()
|
start_sending_opt(senders, metadata, cookies_chan).ok().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For use by loaders in responding to a Load message.
|
/// For use by loaders in responding to a Load message.
|
||||||
pub fn start_sending_opt(senders: ResponseSenders, metadata: Metadata) -> Result<Sender<ProgressMsg>, ()> {
|
pub fn start_sending_opt(senders: ResponseSenders, metadata: Metadata, cookies_chan: Sender<ControlMsg>) -> Result<Sender<ProgressMsg>, ()> {
|
||||||
let (progress_chan, progress_port) = channel();
|
let (progress_chan, progress_port) = channel();
|
||||||
|
let cookies = metadata.cookies.clone();
|
||||||
let result = senders.immediate_consumer.send(TargetedLoadResponse {
|
let result = senders.immediate_consumer.send(TargetedLoadResponse {
|
||||||
load_response: LoadResponse {
|
load_response: LoadResponse {
|
||||||
metadata: metadata,
|
metadata: metadata,
|
||||||
|
@ -154,6 +162,10 @@ pub fn start_sending_opt(senders: ResponseSenders, metadata: Metadata) -> Result
|
||||||
},
|
},
|
||||||
consumer: senders.eventual_consumer
|
consumer: senders.eventual_consumer
|
||||||
});
|
});
|
||||||
|
match cookies_chan.send(ControlMsg::Cookies(cookies)) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(_) => { return Err(()) }
|
||||||
|
}
|
||||||
match result {
|
match result {
|
||||||
Ok(_) => Ok(progress_chan),
|
Ok(_) => Ok(progress_chan),
|
||||||
Err(_) => Err(())
|
Err(_) => Err(())
|
||||||
|
@ -184,8 +196,9 @@ pub type ResourceTask = Sender<ControlMsg>;
|
||||||
pub fn new_resource_task(user_agent: Option<String>) -> ResourceTask {
|
pub fn new_resource_task(user_agent: Option<String>) -> ResourceTask {
|
||||||
let (setup_chan, setup_port) = channel();
|
let (setup_chan, setup_port) = channel();
|
||||||
let sniffer_task = sniffer_task::new_sniffer_task();
|
let sniffer_task = sniffer_task::new_sniffer_task();
|
||||||
|
let setup_chan_clone = setup_chan.clone();
|
||||||
spawn_named("ResourceManager".to_owned(), move || {
|
spawn_named("ResourceManager".to_owned(), move || {
|
||||||
ResourceManager::new(setup_port, user_agent, sniffer_task).start();
|
ResourceManager::new(setup_port, user_agent, sniffer_task, setup_chan_clone).start();
|
||||||
});
|
});
|
||||||
setup_chan
|
setup_chan
|
||||||
}
|
}
|
||||||
|
@ -194,26 +207,35 @@ struct ResourceManager {
|
||||||
from_client: Receiver<ControlMsg>,
|
from_client: Receiver<ControlMsg>,
|
||||||
user_agent: Option<String>,
|
user_agent: Option<String>,
|
||||||
sniffer_task: SnifferTask,
|
sniffer_task: SnifferTask,
|
||||||
|
cookie_storage: CookieStorage,
|
||||||
|
cookies_chan: Sender<ControlMsg>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ResourceManager {
|
impl ResourceManager {
|
||||||
fn new(from_client: Receiver<ControlMsg>, user_agent: Option<String>, sniffer_task: SnifferTask) -> ResourceManager {
|
fn new(from_client: Receiver<ControlMsg>, user_agent: Option<String>, sniffer_task: SnifferTask, cookies_chan: Sender<ControlMsg>) -> ResourceManager {
|
||||||
ResourceManager {
|
ResourceManager {
|
||||||
from_client: from_client,
|
from_client: from_client,
|
||||||
user_agent: user_agent,
|
user_agent: user_agent,
|
||||||
sniffer_task: sniffer_task,
|
sniffer_task: sniffer_task,
|
||||||
|
cookie_storage: CookieStorage::new(),
|
||||||
|
cookies_chan: cookies_chan,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl ResourceManager {
|
impl ResourceManager {
|
||||||
fn start(&self) {
|
fn start(&mut self) {
|
||||||
loop {
|
loop {
|
||||||
match self.from_client.recv().unwrap() {
|
match self.from_client.recv().unwrap() {
|
||||||
ControlMsg::Load(load_data) => {
|
ControlMsg::Load(load_data) => {
|
||||||
self.load(load_data)
|
self.load(load_data)
|
||||||
}
|
}
|
||||||
|
ControlMsg::Cookies(vector) => {
|
||||||
|
for cookie in vector.iter() {
|
||||||
|
self.cookie_storage.push(cookie.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
ControlMsg::Exit => {
|
ControlMsg::Exit => {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -221,9 +243,14 @@ impl ResourceManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load(&self, load_data: LoadData) {
|
fn load(&mut self, load_data: LoadData) {
|
||||||
let mut load_data = load_data;
|
let mut load_data = load_data;
|
||||||
self.user_agent.as_ref().map(|ua| load_data.headers.set(UserAgent(ua.clone())));
|
self.user_agent.as_ref().map(|ua| load_data.headers.set(UserAgent(ua.clone())));
|
||||||
|
if let Some(cookies) = self.cookie_storage.cookies_for_url(load_data.url.clone()) {
|
||||||
|
let mut v = Vec::new();
|
||||||
|
v.push(cookies.into_bytes());
|
||||||
|
load_data.headers.set_raw("cookie".to_owned(), v);
|
||||||
|
}
|
||||||
let senders = ResponseSenders {
|
let senders = ResponseSenders {
|
||||||
immediate_consumer: self.sniffer_task.clone(),
|
immediate_consumer: self.sniffer_task.clone(),
|
||||||
eventual_consumer: load_data.consumer.clone(),
|
eventual_consumer: load_data.consumer.clone(),
|
||||||
|
@ -231,13 +258,13 @@ impl ResourceManager {
|
||||||
|
|
||||||
debug!("resource_task: loading url: {}", load_data.url.serialize());
|
debug!("resource_task: loading url: {}", load_data.url.serialize());
|
||||||
match load_data.url.scheme.as_slice() {
|
match load_data.url.scheme.as_slice() {
|
||||||
"file" => file_loader::factory(load_data, self.sniffer_task.clone()),
|
"file" => file_loader::factory(load_data, self.sniffer_task.clone(), self.cookies_chan.clone()),
|
||||||
"http" | "https" => http_loader::factory(load_data, self.sniffer_task.clone()),
|
"http" | "https" => http_loader::factory(load_data, self.sniffer_task.clone(), self.cookies_chan.clone()),
|
||||||
"data" => data_loader::factory(load_data, self.sniffer_task.clone()),
|
"data" => data_loader::factory(load_data, self.sniffer_task.clone(), self.cookies_chan.clone()),
|
||||||
"about" => about_loader::factory(load_data, self.sniffer_task.clone()),
|
"about" => about_loader::factory(load_data, self.sniffer_task.clone(), self.cookies_chan.clone()),
|
||||||
_ => {
|
_ => {
|
||||||
debug!("resource_task: no loader for scheme {}", load_data.url.scheme);
|
debug!("resource_task: no loader for scheme {}", load_data.url.scheme);
|
||||||
start_sending(senders, Metadata::default(load_data.url))
|
start_sending(senders, Metadata::default(load_data.url), self.cookie_chan.clone())
|
||||||
.send(ProgressMsg::Done(Err("no loader for scheme".to_string()))).unwrap();
|
.send(ProgressMsg::Done(Err("no loader for scheme".to_string()))).unwrap();
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
1
components/servo/Cargo.lock
generated
1
components/servo/Cargo.lock
generated
|
@ -154,6 +154,7 @@ name = "devtools_traits"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"msg 0.0.1",
|
"msg 0.0.1",
|
||||||
|
"util 0.0.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -163,4 +163,3 @@ impl<Window> Browser<Window> where Window: WindowMethods + 'static {
|
||||||
self.compositor.shutdown();
|
self.compositor.shutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue