diff options
author | bors-servo <metajack+bors@gmail.com> | 2015-02-04 11:57:54 -0700 |
---|---|---|
committer | bors-servo <metajack+bors@gmail.com> | 2015-02-04 11:57:54 -0700 |
commit | 7e3f504d94ffb77ec6148166d2ab73978e1c71c8 (patch) | |
tree | c3d04d3b52e8f83197819565c867b52df167b2a5 /components/script | |
parent | 58a3cdcbef30e04199d33dc83cea0ace3e2cfcf1 (diff) | |
parent | 0557f8592cb965658be471d8807a2404483c0806 (diff) | |
download | servo-7e3f504d94ffb77ec6148166d2ab73978e1c71c8.tar.gz servo-7e3f504d94ffb77ec6148166d2ab73978e1c71c8.zip |
auto merge of #4519 : jdm/servo/cookies, r=Ms2ger
As specified in http://tools.ietf.org/html/rfc6265. Requires https://github.com/servo/cookie-rs/pull/1. Tested against http://www.joshmatthews.net/cookie.php, http://www.html-kit.com/tools/cookietester/, https://github.com/login, and https://mobile.twitter.com/session/new .
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/Cargo.toml | 4 | ||||
-rw-r--r-- | components/script/dom/document.rs | 43 | ||||
-rw-r--r-- | components/script/dom/element.rs | 4 | ||||
-rw-r--r-- | components/script/dom/htmlformelement.rs | 13 | ||||
-rw-r--r-- | components/script/dom/node.rs | 2 | ||||
-rw-r--r-- | components/script/dom/webidls/Document.webidl | 2 | ||||
-rw-r--r-- | components/script/dom/xmlhttprequest.rs | 62 | ||||
-rw-r--r-- | components/script/script_task.rs | 93 |
8 files changed, 132 insertions, 91 deletions
diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml index e0b98db4f4b..8b4d56891be 100644 --- a/components/script/Cargo.toml +++ b/components/script/Cargo.toml @@ -50,7 +50,7 @@ git = "https://github.com/servo/html5ever" [dependencies.hyper] git = "https://github.com/servo/hyper" -branch = "servo" +branch = "old_servo_new_cookies" [dependencies.js] git = "https://github.com/servo/rust-mozjs" @@ -67,4 +67,4 @@ git = "https://github.com/servo/string-cache" [dependencies] encoding = "0.2" url = "0.2.16" -time = "0.1.12"
\ No newline at end of file +time = "0.1.12" diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index b6a5659a88a..3734527bc09 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -19,7 +19,7 @@ use dom::bindings::codegen::InheritTypes::{HTMLAreaElementDerived, HTMLEmbedElem use dom::bindings::codegen::InheritTypes::{HTMLFormElementDerived, HTMLImageElementDerived}; use dom::bindings::codegen::InheritTypes::{HTMLScriptElementDerived}; use dom::bindings::error::{ErrorResult, Fallible}; -use dom::bindings::error::Error::{NotSupported, InvalidCharacter}; +use dom::bindings::error::Error::{NotSupported, InvalidCharacter, Security}; use dom::bindings::error::Error::{HierarchyRequest, NamespaceError}; use dom::bindings::global::GlobalRef; use dom::bindings::js::{MutNullableJS, JS, JSRef, LayoutJS, Temporary, TemporaryPushable}; @@ -54,6 +54,8 @@ use dom::range::Range; use dom::treewalker::TreeWalker; use dom::uievent::UIEvent; use dom::window::{Window, WindowHelpers}; +use net::resource_task::ControlMsg::{SetCookiesForUrl, GetCookiesForUrl}; +use net::cookie_storage::CookieSource::NonHTTP; use util::namespace; use util::str::{DOMString, split_html_space_chars}; @@ -68,6 +70,7 @@ use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::ascii::AsciiExt; use std::cell::{Cell, Ref}; use std::default::Default; +use std::sync::mpsc::channel; use time; #[derive(PartialEq)] @@ -170,7 +173,7 @@ pub trait DocumentHelpers<'a> { fn window(self) -> Temporary<Window>; fn encoding_name(self) -> Ref<'a, DOMString>; fn is_html_document(self) -> bool; - fn url(self) -> &'a Url; + fn url(self) -> Url; fn quirks_mode(self) -> QuirksMode; fn set_quirks_mode(self, mode: QuirksMode); fn set_last_modified(self, value: DOMString); @@ -206,8 +209,9 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> { self.is_html_document } - fn url(self) -> &'a Url { - &self.extended_deref().url + // http://dom.spec.whatwg.org/#dom-document-url + fn url(self) -> Url { + self.url.clone() } fn quirks_mode(self) -> QuirksMode { @@ -1003,7 +1007,38 @@ impl<'a> DocumentMethods for JSRef<'a, Document> { Temporary::new(self.window) } + // https://html.spec.whatwg.org/multipage/dom.html#dom-document-cookie + fn GetCookie(self) -> Fallible<DOMString> { + //TODO: return empty string for cookie-averse Document + let url = self.url(); + if !is_scheme_host_port_tuple(&url) { + return Err(Security); + } + let window = self.window.root(); + let page = window.page(); + let (tx, rx) = channel(); + let _ = page.resource_task.send(GetCookiesForUrl(url, tx, NonHTTP)); + let cookies = rx.recv().unwrap(); + Ok(cookies.unwrap_or("".to_owned())) + } + + // https://html.spec.whatwg.org/multipage/dom.html#dom-document-cookie + fn SetCookie(self, cookie: DOMString) -> ErrorResult { + //TODO: ignore for cookie-averse Document + let url = self.url(); + if !is_scheme_host_port_tuple(&url) { + return Err(Security); + } + let window = self.window.root(); + let page = window.page(); + let _ = page.resource_task.send(SetCookiesForUrl(url, cookie, NonHTTP)); + Ok(()) + } + global_event_handlers!(); event_handler!(readystatechange, GetOnreadystatechange, SetOnreadystatechange); } +fn is_scheme_host_port_tuple(url: &Url) -> bool { + url.host().is_some() && url.port_or_default().is_some() +} diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index b1b458bad40..69eb3f2ee23 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -777,7 +777,7 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> { let base = doc.r().url(); // https://html.spec.whatwg.org/multipage/infrastructure.html#reflect // XXXManishearth this doesn't handle `javascript:` urls properly - match UrlParser::new().base_url(base).parse(url.as_slice()) { + match UrlParser::new().base_url(&base).parse(url.as_slice()) { Ok(parsed) => parsed.serialize(), Err(_) => "".to_owned() } @@ -1174,7 +1174,7 @@ impl<'a> VirtualMethods for JSRef<'a, Element> { // Modifying the `style` attribute might change style. let node: JSRef<Node> = NodeCast::from_ref(*self); let doc = document_from_node(*self).root(); - let base_url = doc.r().url().clone(); + let base_url = doc.r().url(); let value = attr.value(); let style = Some(parse_style_attribute(value.as_slice(), &base_url)); *self.style_attribute.borrow_mut() = style; diff --git a/components/script/dom/htmlformelement.rs b/components/script/dom/htmlformelement.rs index 5f0ec3f212a..74f789ab491 100644 --- a/components/script/dom/htmlformelement.rs +++ b/components/script/dom/htmlformelement.rs @@ -23,6 +23,8 @@ use dom::htmlbuttonelement::{HTMLButtonElement}; use dom::htmltextareaelement::{HTMLTextAreaElement, HTMLTextAreaElementHelpers}; use dom::node::{Node, NodeHelpers, NodeTypeId, document_from_node, window_from_node}; use hyper::method::Method; +use hyper::header::common::ContentType; +use hyper::mime; use servo_msg::constellation_msg::LoadData; use util::str::DOMString; use script_task::{ScriptChan, ScriptMsg}; @@ -178,7 +180,7 @@ impl<'a> HTMLFormElementHelpers for JSRef<'a, HTMLFormElement> { } // TODO: Resolve the url relative to the submitter element // Step 10-15 - let action_components = UrlParser::new().base_url(base).parse(action.as_slice()).unwrap_or(base.clone()); + let action_components = UrlParser::new().base_url(&base).parse(action.as_slice()).unwrap_or(base); let _action = action_components.serialize(); let scheme = action_components.scheme.clone(); let enctype = submitter.enctype(); @@ -186,12 +188,17 @@ impl<'a> HTMLFormElementHelpers for JSRef<'a, HTMLFormElement> { let _target = submitter.target(); // TODO: Handle browsing contexts, partially loaded documents (step 16-17) + let mut load_data = LoadData::new(action_components); + let parsed_data = match enctype { - FormEncType::UrlEncoded => serialize(form_data.iter().map(|d| (d.name.as_slice(), d.value.as_slice()))), + FormEncType::UrlEncoded => { + let mime: mime::Mime = "application/x-www-form-urlencoded".parse().unwrap(); + load_data.headers.set(ContentType(mime)); + serialize(form_data.iter().map(|d| (d.name.as_slice(), d.value.as_slice()))) + } _ => "".to_owned() // TODO: Add serializers for the other encoding types }; - let mut load_data = LoadData::new(action_components); // Step 18 match (scheme.as_slice(), method) { (_, FormMethod::FormDialog) => return, // Unimplemented diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 745c5a3a135..cdd52e78855 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -1574,7 +1574,7 @@ impl Node { false => IsHTMLDocument::NonHTMLDocument, }; let window = document.window().root(); - let document = Document::new(window.r(), Some(document.url().clone()), + let document = Document::new(window.r(), Some(document.url()), is_html_doc, None, DocumentSource::NotFromParser); NodeCast::from_temporary(document) diff --git a/components/script/dom/webidls/Document.webidl b/components/script/dom/webidls/Document.webidl index 92b7f35c34b..26d2fa03163 100644 --- a/components/script/dom/webidls/Document.webidl +++ b/components/script/dom/webidls/Document.webidl @@ -65,6 +65,8 @@ partial interface Document { readonly attribute DocumentReadyState readyState; readonly attribute DOMString lastModified; readonly attribute Location location; + [Throws] + attribute DOMString cookie; // DOM tree accessors [SetterThrows] diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index a32045cff75..f9f75fbbf7e 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -561,41 +561,35 @@ impl<'a> XMLHttpRequestMethods for JSRef<'a, XMLHttpRequest> { let mut load_data = LoadData::new(self.request_url.borrow().clone().unwrap(), start_chan); load_data.data = extracted; - // Default headers - { - #[inline] - fn join_raw(a: &str, b: &str) -> Vec<u8> { - let len = a.len() + b.len(); - let mut vec = Vec::with_capacity(len); - vec.push_all(a.as_bytes()); - vec.push_all(b.as_bytes()); - vec - } - let ref mut request_headers = self.request_headers.borrow_mut(); - if !request_headers.has::<ContentType>() { - // XHR spec differs from http, and says UTF-8 should be in capitals, - // instead of "utf-8", which is what Hyper defaults to. - let params = ";charset=UTF-8"; - let n = "content-type"; - match data { - Some(eString(_)) => - request_headers.set_raw(n.to_owned(), vec![join_raw("text/plain", params)]), - Some(eURLSearchParams(_)) => - request_headers.set_raw( - n.to_owned(), vec![join_raw("application/x-www-form-urlencoded", params)]), - None => () - } - } + #[inline] + fn join_raw(a: &str, b: &str) -> Vec<u8> { + let len = a.len() + b.len(); + let mut vec = Vec::with_capacity(len); + vec.push_all(a.as_bytes()); + vec.push_all(b.as_bytes()); + vec + } + // XHR spec differs from http, and says UTF-8 should be in capitals, + // instead of "utf-8", which is what Hyper defaults to. + let params = ";charset=UTF-8"; + let n = "content-type"; + match data { + Some(eString(_)) => + load_data.headers.set_raw(n.to_owned(), vec![join_raw("text/plain", params)]), + Some(eURLSearchParams(_)) => + load_data.headers.set_raw( + n.to_owned(), vec![join_raw("application/x-www-form-urlencoded", params)]), + None => () + } - if !request_headers.has::<Accept>() { - let mime = Mime(mime::TopLevel::Star, mime::SubLevel::Star, vec![]); - request_headers.set( - Accept(vec![QualityItem::new(mime, 1.0)])); - } - } // drops the borrow_mut + load_data.preserved_headers = (*self.request_headers.borrow()).clone(); + + if !load_data.preserved_headers.has::<Accept>() { + let mime = Mime(mime::TopLevel::Star, mime::SubLevel::Star, vec![]); + load_data.preserved_headers.set(Accept(vec![QualityItem::new(mime, 1.0)])); + } - load_data.headers = (*self.request_headers.borrow()).clone(); load_data.method = (*self.request_method.borrow()).clone(); let (terminate_sender, terminate_receiver) = channel(); *self.terminate_sender.borrow_mut() = Some(terminate_sender); @@ -607,8 +601,10 @@ impl<'a> XMLHttpRequestMethods for JSRef<'a, XMLHttpRequest> { } else { RequestMode::CORS }; + let mut combined_headers = load_data.headers.clone(); + combined_headers.extend(load_data.preserved_headers.iter()); let cors_request = CORSRequest::maybe_new(referer_url.clone(), load_data.url.clone(), mode, - load_data.method.clone(), load_data.headers.clone()); + load_data.method.clone(), combined_headers); match cors_request { Ok(None) => { let mut buf = String::new(); diff --git a/components/script/script_task.rs b/components/script/script_task.rs index 35f85f593c9..2d64f53b396 100644 --- a/components/script/script_task.rs +++ b/components/script/script_task.rs @@ -67,7 +67,7 @@ use util::task::spawn_named_with_send_on_failure; use util::task_state; use geom::point::Point2D; -use hyper::header::{Header, HeaderFormat}; +use hyper::header::{Header, Headers, HeaderFormat}; use hyper::header::shared::util as header_util; use js::jsapi::{JS_SetWrapObjectCallbacks, JS_SetGCZeal, JS_DEFAULT_ZEAL_FREQ, JS_GC}; use js::jsapi::{JSContext, JSRuntime, JSObject}; @@ -787,6 +787,44 @@ impl ScriptTask { let is_javascript = url.scheme.as_slice() == "javascript"; + self.compositor.borrow_mut().set_ready_state(pipeline_id, Loading); + + let (mut parser_input, final_url, last_modified) = if !is_javascript { + // Wait for the LoadResponse so that the parser knows the final URL. + let (input_chan, input_port) = channel(); + self.resource_task.send(ControlMsg::Load(NetLoadData { + url: url, + method: load_data.method, + headers: Headers::new(), + preserved_headers: load_data.headers, + data: load_data.data, + cors: None, + consumer: input_chan, + })).unwrap(); + + let load_response = input_port.recv().unwrap(); + + let last_modified = load_response.metadata.headers.as_ref().and_then(|headers| { + headers.get().map(|&LastModified(ref tm)| tm.clone()) + }); + + let final_url = load_response.metadata.final_url.clone(); + + (Some(HTMLInput::InputUrl(load_response)), final_url, last_modified) + } else { + let doc_url = last_url.unwrap_or_else(|| { + Url::parse("about:blank").unwrap() + }); + (None, doc_url, None) + }; + + // Store the final URL before we start parsing, so that DOM routines + // (e.g. HTMLImageElement::update_image) can resolve relative URLs + // correctly. + { + *page.mut_url() = Some((final_url.clone(), true)); + } + let cx = self.js_context.borrow(); let cx = cx.as_ref().unwrap(); // Create the window and document objects. @@ -796,22 +834,15 @@ impl ScriptTask { self.control_chan.clone(), self.compositor.borrow_mut().dup(), self.image_cache_task.clone()).root(); - let doc_url = if is_javascript { - let doc_url = last_url.unwrap_or_else(|| { - Url::parse("about:blank").unwrap() - }); - *page.mut_url() = Some((doc_url.clone(), true)); - doc_url - } else { - url.clone() - }; - let document = Document::new(window.r(), Some(doc_url.clone()), + + let document = Document::new(window.r(), Some(final_url.clone()), IsHTMLDocument::HTMLDocument, None, DocumentSource::FromParser).root(); - + if let Some(tm) = last_modified { + document.set_last_modified(dom_last_modified(&tm)); + } window.r().init_browser_context(document.r()); - self.compositor.borrow_mut().set_ready_state(pipeline_id, Loading); { // Create the root frame. @@ -822,45 +853,15 @@ impl ScriptTask { }); } - let (parser_input, final_url) = if !is_javascript { - // Wait for the LoadResponse so that the parser knows the final URL. - let (input_chan, input_port) = channel(); - self.resource_task.send(ControlMsg::Load(NetLoadData { - url: url, - method: load_data.method, - headers: load_data.headers, - data: load_data.data, - cors: None, - consumer: input_chan, - })).unwrap(); - - let load_response = input_port.recv().unwrap(); - - load_response.metadata.headers.as_ref().map(|headers| { - headers.get().map(|&LastModified(ref tm)| { - document.r().set_last_modified(dom_last_modified(tm)); - }); - }); - - let final_url = load_response.metadata.final_url.clone(); - - { - // Store the final URL before we start parsing, so that DOM routines - // (e.g. HTMLImageElement::update_image) can resolve relative URLs - // correctly. - *page.mut_url() = Some((final_url.clone(), true)); - } - - (HTMLInput::InputUrl(load_response), final_url) - } else { + if is_javascript { let evalstr = load_data.url.non_relative_scheme_data().unwrap(); let jsval = window.r().evaluate_js_on_global_with_result(evalstr); let strval = FromJSValConvertible::from_jsval(self.get_cx(), jsval, StringificationBehavior::Empty); - (HTMLInput::InputString(strval.unwrap_or("".to_owned())), doc_url) + parser_input = Some(HTMLInput::InputString(strval.unwrap_or("".to_owned()))); }; - parse_html(document.r(), parser_input, &final_url); + parse_html(document.r(), parser_input.unwrap(), &final_url); document.r().set_ready_state(DocumentReadyState::Interactive); self.compositor.borrow_mut().set_ready_state(pipeline_id, PerformingLayout); |