aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeegan McAllister <kmcallister@mozilla.com>2013-09-23 12:13:33 -0700
committerKeegan McAllister <kmcallister@mozilla.com>2013-09-23 14:50:50 -0700
commit1c6de361b735a80034edb719d997e6c8b6cd8fef (patch)
tree32d6ee00b1a41571f1bbb15af7786350ed456449
parent9bd0e2a3ac41ee563981f37567b73ca309216568 (diff)
downloadservo-1c6de361b735a80034edb719d997e6c8b6cd8fef.tar.gz
servo-1c6de361b735a80034edb719d997e6c8b6cd8fef.zip
Handle HTTP 3xx redirects
Fixes #973.
-rw-r--r--src/components/net/http_loader.rs25
-rw-r--r--src/components/net/image_cache_task.rs1
-rw-r--r--src/components/net/resource_task.rs3
-rw-r--r--src/components/script/html/cssparse.rs17
-rw-r--r--src/components/script/html/hubbub_html_parser.rs35
-rw-r--r--src/components/script/script_task.rs4
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.
//