diff options
author | Keegan McAllister <kmcallister@mozilla.com> | 2013-09-23 12:13:33 -0700 |
---|---|---|
committer | Keegan McAllister <kmcallister@mozilla.com> | 2013-09-23 14:50:50 -0700 |
commit | 1c6de361b735a80034edb719d997e6c8b6cd8fef (patch) | |
tree | 32d6ee00b1a41571f1bbb15af7786350ed456449 | |
parent | 9bd0e2a3ac41ee563981f37567b73ca309216568 (diff) | |
download | servo-1c6de361b735a80034edb719d997e6c8b6cd8fef.tar.gz servo-1c6de361b735a80034edb719d997e6c8b6cd8fef.zip |
Handle HTTP 3xx redirects
Fixes #973.
-rw-r--r-- | src/components/net/http_loader.rs | 25 | ||||
-rw-r--r-- | src/components/net/image_cache_task.rs | 1 | ||||
-rw-r--r-- | src/components/net/resource_task.rs | 3 | ||||
-rw-r--r-- | src/components/script/html/cssparse.rs | 17 | ||||
-rw-r--r-- | src/components/script/html/hubbub_html_parser.rs | 35 | ||||
-rw-r--r-- | src/components/script/script_task.rs | 4 |
6 files changed, 70 insertions, 15 deletions
diff --git a/src/components/net/http_loader.rs b/src/components/net/http_loader.rs index 88ca509827a..e06fe90ccf7 100644 --- a/src/components/net/http_loader.rs +++ b/src/components/net/http_loader.rs @@ -2,7 +2,7 @@ * 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::{ProgressMsg, Payload, Done, LoaderTask}; +use resource_task::{ProgressMsg, Payload, Done, UrlChange, LoaderTask}; use std::cell::Cell; use std::vec; @@ -22,7 +22,7 @@ pub fn factory() -> LoaderTask { } fn load(url: Url, progress_chan: Chan<ProgressMsg>) { - assert!(url.scheme == ~"http"); + assert!("http" == url.scheme); info!("requesting %s", url.to_str()); @@ -35,8 +35,27 @@ fn load(url: Url, progress_chan: Chan<ProgressMsg>) { } }; + info!("got HTTP response %s, headers:", response.status.to_str()) + + let is_redirect = 3 == (response.status.code() / 100); + let mut redirect: Option<Url> = None; for header in response.headers.iter() { - info!(" - %s: %s", header.header_name(), header.header_value()); + let name = header.header_name(); + let value = header.header_value(); + info!(" - %s: %s", name, value); + if is_redirect && ("Location" == name) { + redirect = Some(FromStr::from_str(value).expect("Failed to parse redirect URL")); + } + } + + // FIXME: detect redirect loops + match redirect { + Some(url) => { + info!("redirecting to %s", url.to_str()); + progress_chan.send(UrlChange(url.clone())); + return load(url, progress_chan); + } + None => () } loop { diff --git a/src/components/net/image_cache_task.rs b/src/components/net/image_cache_task.rs index a6f3dfb529f..ada3fe53678 100644 --- a/src/components/net/image_cache_task.rs +++ b/src/components/net/image_cache_task.rs @@ -444,6 +444,7 @@ fn load_image_data(url: Url, resource_task: ResourceTask) -> Result<~[u8], ()> { loop { match response_port.recv() { + resource_task::UrlChange(*) => (), // don't care that URL changed resource_task::Payload(data) => { image_data.push_all(data); } diff --git a/src/components/net/resource_task.rs b/src/components/net/resource_task.rs index c2b79f61f7d..7a95b055529 100644 --- a/src/components/net/resource_task.rs +++ b/src/components/net/resource_task.rs @@ -21,6 +21,9 @@ pub enum ControlMsg { /// Messages sent in response to a `Load` message #[deriving(Eq)] pub enum ProgressMsg { + /// URL changed due to a redirect. There can be zero or more of these, + /// but they are guaranteed to arrive before messages of any other type. + UrlChange(Url), /// Binary data - there may be multiple of these Payload(~[u8]), /// Indicates loading is complete, either successfully or not diff --git a/src/components/script/html/cssparse.rs b/src/components/script/html/cssparse.rs index 6d9d0d18a5a..9111f517c12 100644 --- a/src/components/script/html/cssparse.rs +++ b/src/components/script/html/cssparse.rs @@ -10,7 +10,7 @@ use std::comm::Port; use std::task; use newcss::stylesheet::Stylesheet; use newcss::util::DataStream; -use servo_net::resource_task::{ResourceTask, ProgressMsg, Load, Payload, Done}; +use servo_net::resource_task::{ResourceTask, ProgressMsg, Load, Payload, Done, UrlChange}; use extra::url::Url; /// Where a style sheet comes from. @@ -57,10 +57,19 @@ fn data_stream(provenance: StylesheetProvenance, resource_task: ResourceTask) -> fn resource_port_to_data_stream(input_port: Port<ProgressMsg>) -> DataStream { return || { - match input_port.recv() { - Payload(data) => Some(data), - Done(*) => None + // Can't just 'return' the value since we're inside a lambda + let mut result = None; + loop { + match input_port.recv() { + UrlChange(*) => (), // don't care that URL changed + Payload(data) => { + result = Some(data); + break; + } + Done(*) => break + } } + result } } diff --git a/src/components/script/html/hubbub_html_parser.rs b/src/components/script/html/hubbub_html_parser.rs index 85bab19b340..523e7dabe3c 100644 --- a/src/components/script/html/hubbub_html_parser.rs +++ b/src/components/script/html/hubbub_html_parser.rs @@ -24,7 +24,7 @@ use std::from_str::FromStr; use hubbub::hubbub; use servo_msg::constellation_msg::{ConstellationChan, SubpageId}; use servo_net::image_cache_task::ImageCacheTask; -use servo_net::resource_task::{Done, Load, Payload, ResourceTask}; +use servo_net::resource_task::{ProgressMsg, Done, Load, Payload, UrlChange, ResourceTask}; use servo_util::tree::TreeNodeRef; use servo_util::url::make_url; use extra::url::Url; @@ -98,6 +98,7 @@ pub enum HtmlDiscoveryMessage { pub struct HtmlParserResult { root: AbstractNode<ScriptView>, discovery_port: Port<HtmlDiscoveryMessage>, + url: Url, } trait NodeWrapping { @@ -171,6 +172,7 @@ fn js_script_listener(to_parent: SharedChan<HtmlDiscoveryMessage>, let mut buf = ~[]; loop { match input_port.recv() { + UrlChange(*) => (), // don't care that URL changed Payload(data) => { buf.push_all(data); } @@ -329,8 +331,25 @@ pub fn parse_html(cx: *JSContext, } let js_chan = SharedChan::new(js_msg_chan); - let url2 = url.clone(); - let url3 = url.clone(); + // Process any UrlChange messages before we build the parser, because the + // tree handler functions need to know the final URL. + let mut final_url = url.clone(); + let (input_port, input_chan) = comm::stream(); + resource_task.send(Load(url.clone(), input_chan)); + let mut progress_msg: ProgressMsg; + loop { + progress_msg = input_port.recv(); + match progress_msg { + UrlChange(url) => { + debug!("page URL changed to %s", url.to_str()); + final_url = url; + } + _ => break + } + } + + let url2 = final_url.clone(); + let url3 = final_url.clone(); // Build the root node. let root = @HTMLHtmlElement { htmlelement: HTMLElement::new(HTMLHtmlElementTypeId, ~"html") }; @@ -551,11 +570,13 @@ pub fn parse_html(cx: *JSContext, }); debug!("set tree handler"); - let (input_port, input_chan) = comm::stream(); - resource_task.send(Load(url.clone(), input_chan)); debug!("loaded page"); loop { - match input_port.recv() { + // We already have a message from the earlier UrlChange processing. + match progress_msg { + UrlChange(*) => { + fail!("got UrlChange message after others"); + } Payload(data) => { debug!("received data"); parser.parse_chunk(data); @@ -567,6 +588,7 @@ pub fn parse_html(cx: *JSContext, break; } } + progress_msg = input_port.recv(); } css_chan.send(CSSTaskExit); @@ -575,6 +597,7 @@ pub fn parse_html(cx: *JSContext, HtmlParserResult { root: root, discovery_port: discovery_port, + url: final_url, } } diff --git a/src/components/script/script_task.rs b/src/components/script/script_task.rs index 8c800727657..da6f75f02d9 100644 --- a/src/components/script/script_task.rs +++ b/src/components/script/script_task.rs @@ -653,7 +653,7 @@ impl ScriptTask { page.next_subpage_id.clone(), self.constellation_chan.clone()); - let HtmlParserResult {root, discovery_port} = html_parsing_result; + let HtmlParserResult {root, discovery_port, url: final_url} = html_parsing_result; let document = HTMLDocument::new(root, Some(window)); @@ -662,7 +662,7 @@ impl ScriptTask { document: document, window: window, }); - page.url = Some((url.clone(), true)); + page.url = Some((final_url, true)); // Send style sheets over to layout. // |