diff options
author | Josh Matthews <josh@joshmatthews.net> | 2015-02-02 20:45:42 +0000 |
---|---|---|
committer | Josh Matthews <josh@joshmatthews.net> | 2015-02-04 13:37:01 +0000 |
commit | fb217ab24b28f41526b8024fa3f4d6266e50e746 (patch) | |
tree | fef7bae6f70cedd44c6a564116048d8c9ee6b88a | |
parent | 542e8d52d586590872b4bf0148d3d25fbfa67555 (diff) | |
download | servo-fb217ab24b28f41526b8024fa3f4d6266e50e746.tar.gz servo-fb217ab24b28f41526b8024fa3f4d6266e50e746.zip |
Make XMLHttpRequest user-set headers be preserved across redirects.
-rw-r--r-- | components/net/http_loader.rs | 19 | ||||
-rw-r--r-- | components/net/resource_task.rs | 4 | ||||
-rw-r--r-- | components/script/dom/xmlhttprequest.rs | 62 | ||||
-rw-r--r-- | components/script/script_task.rs | 5 |
4 files changed, 49 insertions, 41 deletions
diff --git a/components/net/http_loader.rs b/components/net/http_loader.rs index 95ecd161aff..f06323ac348 100644 --- a/components/net/http_loader.rs +++ b/components/net/http_loader.rs @@ -108,22 +108,29 @@ reason: \"certificate verify failed\" }]"; } }; + // Preserve the `host` header set automatically by Request. + let host = req.headers().get::<Host>().unwrap().clone(); + // Avoid automatically preserving request headers when redirects occur. // See https://bugzilla.mozilla.org/show_bug.cgi?id=401564 and - // https://bugzilla.mozilla.org/show_bug.cgi?id=216828 + // https://bugzilla.mozilla.org/show_bug.cgi?id=216828 . + // Only preserve ones which have been explicitly marked as such. if iters == 1 { - // Preserve the `host` header set automatically by Request. - let host = req.headers().get::<Host>().unwrap().clone(); - *req.headers_mut() = load_data.headers.clone(); - req.headers_mut().set(host); + let mut combined_headers = load_data.headers.clone(); + combined_headers.extend(load_data.preserved_headers.iter()); + *req.headers_mut() = combined_headers; + } else { + *req.headers_mut() = load_data.preserved_headers.clone(); } + req.headers_mut().set(host); + let (tx, rx) = channel(); cookies_chan.send(ControlMsg::GetCookiesForUrl(url.clone(), tx, CookieSource::HTTP)); if let Some(cookie_list) = rx.recv().unwrap() { let mut v = Vec::new(); v.push(cookie_list.into_bytes()); - load_data.headers.set_raw("Cookie".to_owned(), v); + req.headers_mut().set_raw("Cookie".to_owned(), v); } // FIXME(seanmonstar): use AcceptEncoding from Hyper once available diff --git a/components/net/resource_task.rs b/components/net/resource_task.rs index cdd62c67abf..14aacc5d451 100644 --- a/components/net/resource_task.rs +++ b/components/net/resource_task.rs @@ -40,7 +40,10 @@ pub enum ControlMsg { pub struct LoadData { pub url: Url, pub method: Method, + /// Headers that will apply to the initial request only pub headers: Headers, + /// Headers that will apply to the initial request and any redirects + pub preserved_headers: Headers, pub data: Option<Vec<u8>>, pub cors: Option<ResourceCORSData>, pub consumer: Sender<LoadResponse>, @@ -52,6 +55,7 @@ impl LoadData { url: url, method: Method::Get, headers: Headers::new(), + preserved_headers: Headers::new(), data: None, cors: None, consumer: consumer, 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 d374cfcf9ba..71f34c9330f 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}; @@ -795,7 +795,8 @@ impl ScriptTask { self.resource_task.send(ControlMsg::Load(NetLoadData { url: url, method: load_data.method, - headers: load_data.headers, + headers: Headers::new(), + preserved_headers: load_data.headers, data: load_data.data, cors: None, consumer: input_chan, |