auto merge of #977 : kmcallister/servo/redirect, r=jdm

This commit is contained in:
bors-servo 2013-09-24 12:45:44 -07:00
commit b7d186dec2
6 changed files with 90 additions and 41 deletions

View file

@ -2,7 +2,7 @@
* 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 resource_task::{ProgressMsg, Payload, Done, LoaderTask}; use resource_task::{ProgressMsg, Payload, Done, UrlChange, LoaderTask};
use std::cell::Cell; use std::cell::Cell;
use std::vec; use std::vec;
@ -22,7 +22,7 @@ pub fn factory() -> LoaderTask {
} }
fn load(url: Url, progress_chan: Chan<ProgressMsg>) { fn load(url: Url, progress_chan: Chan<ProgressMsg>) {
assert!(url.scheme == ~"http"); assert!("http" == url.scheme);
info!("requesting %s", url.to_str()); 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() { 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 { loop {

View file

@ -444,6 +444,7 @@ fn load_image_data(url: Url, resource_task: ResourceTask) -> Result<~[u8], ()> {
loop { loop {
match response_port.recv() { match response_port.recv() {
resource_task::UrlChange(*) => (), // don't care that URL changed
resource_task::Payload(data) => { resource_task::Payload(data) => {
image_data.push_all(data); image_data.push_all(data);
} }

View file

@ -21,6 +21,9 @@ pub enum ControlMsg {
/// Messages sent in response to a `Load` message /// Messages sent in response to a `Load` message
#[deriving(Eq)] #[deriving(Eq)]
pub enum ProgressMsg { 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 /// Binary data - there may be multiple of these
Payload(~[u8]), Payload(~[u8]),
/// Indicates loading is complete, either successfully or not /// Indicates loading is complete, either successfully or not

View file

@ -10,7 +10,7 @@ use std::comm::Port;
use std::task; use std::task;
use newcss::stylesheet::Stylesheet; use newcss::stylesheet::Stylesheet;
use newcss::util::DataStream; 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; use extra::url::Url;
/// Where a style sheet comes from. /// 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 { fn resource_port_to_data_stream(input_port: Port<ProgressMsg>) -> DataStream {
return || { return || {
match input_port.recv() { // Can't just 'return' the value since we're inside a lambda
Payload(data) => Some(data), let mut result = None;
Done(*) => None loop {
match input_port.recv() {
UrlChange(*) => (), // don't care that URL changed
Payload(data) => {
result = Some(data);
break;
}
Done(*) => break
}
} }
result
} }
} }

View file

@ -24,7 +24,7 @@ use std::from_str::FromStr;
use hubbub::hubbub; use hubbub::hubbub;
use servo_msg::constellation_msg::{ConstellationChan, SubpageId}; use servo_msg::constellation_msg::{ConstellationChan, SubpageId};
use servo_net::image_cache_task::ImageCacheTask; 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::tree::TreeNodeRef;
use servo_util::url::make_url; use servo_util::url::make_url;
use extra::url::Url; use extra::url::Url;
@ -98,6 +98,7 @@ pub enum HtmlDiscoveryMessage {
pub struct HtmlParserResult { pub struct HtmlParserResult {
root: AbstractNode<ScriptView>, root: AbstractNode<ScriptView>,
discovery_port: Port<HtmlDiscoveryMessage>, discovery_port: Port<HtmlDiscoveryMessage>,
url: Url,
} }
trait NodeWrapping { trait NodeWrapping {
@ -171,6 +172,7 @@ fn js_script_listener(to_parent: SharedChan<HtmlDiscoveryMessage>,
let mut buf = ~[]; let mut buf = ~[];
loop { loop {
match input_port.recv() { match input_port.recv() {
UrlChange(*) => (), // don't care that URL changed
Payload(data) => { Payload(data) => {
buf.push_all(data); buf.push_all(data);
} }
@ -329,8 +331,25 @@ pub fn parse_html(cx: *JSContext,
} }
let js_chan = SharedChan::new(js_msg_chan); let js_chan = SharedChan::new(js_msg_chan);
let url2 = url.clone(); // Process any UrlChange messages before we build the parser, because the
let url3 = url.clone(); // 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. // Build the root node.
let root = @HTMLHtmlElement { htmlelement: HTMLElement::new(HTMLHtmlElementTypeId, ~"html") }; let root = @HTMLHtmlElement { htmlelement: HTMLElement::new(HTMLHtmlElementTypeId, ~"html") };
@ -500,37 +519,31 @@ pub fn parse_html(cx: *JSContext,
debug!("encoding change"); debug!("encoding change");
}, },
complete_script: |script| { complete_script: |script| {
// A little function for holding this lint attr unsafe {
fn complete_script(script: hubbub::NodeDataPtr, let scriptnode: AbstractNode<ScriptView> = NodeWrapping::from_hubbub_node(script);
url: Url, do scriptnode.with_imm_element |script| {
js_chan: SharedChan<JSMessage>) { match script.get_attr("src") {
unsafe { Some(src) => {
let scriptnode: AbstractNode<ScriptView> = NodeWrapping::from_hubbub_node(script); debug!("found script: %s", src);
do scriptnode.with_imm_element |script| { let new_url = make_url(src.to_str(), Some(url3.clone()));
match script.get_attr("src") { js_chan2.send(JSTaskNewFile(new_url));
Some(src) => { }
debug!("found script: %s", src); None => {
let new_url = make_url(src.to_str(), Some(url.clone())); let mut data = ~[];
js_chan.send(JSTaskNewFile(new_url)); debug!("iterating over children %?", scriptnode.first_child());
} for child in scriptnode.children() {
None => { debug!("child = %?", child);
let mut data = ~[]; do child.with_imm_text() |text| {
debug!("iterating over children %?", scriptnode.first_child()); data.push(text.element.data.to_str()); // FIXME: Bad copy.
for child in scriptnode.children() {
debug!("child = %?", child);
do child.with_imm_text() |text| {
data.push(text.element.data.to_str()); // FIXME: Bad copy.
}
} }
debug!("data = %?", data);
js_chan.send(JSTaskNewInlineScript(data.concat(), url.clone()));
} }
debug!("script data = %?", data);
js_chan2.send(JSTaskNewInlineScript(data.concat(), url3.clone()));
} }
} }
} }
} }
complete_script(script, url3.clone(), js_chan2.clone());
debug!("complete script"); debug!("complete script");
}, },
complete_style: |style| { complete_style: |style| {
@ -549,7 +562,7 @@ pub fn parse_html(cx: *JSContext,
} }
} }
debug!("data = %?", data); debug!("style data = %?", data);
let provenance = InlineProvenance(url_cell.take().unwrap(), data.concat()); let provenance = InlineProvenance(url_cell.take().unwrap(), data.concat());
css_chan3.send(CSSTaskNewFile(provenance)); css_chan3.send(CSSTaskNewFile(provenance));
} }
@ -557,11 +570,13 @@ pub fn parse_html(cx: *JSContext,
}); });
debug!("set tree handler"); debug!("set tree handler");
let (input_port, input_chan) = comm::stream();
resource_task.send(Load(url.clone(), input_chan));
debug!("loaded page"); debug!("loaded page");
loop { 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) => { Payload(data) => {
debug!("received data"); debug!("received data");
parser.parse_chunk(data); parser.parse_chunk(data);
@ -573,6 +588,7 @@ pub fn parse_html(cx: *JSContext,
break; break;
} }
} }
progress_msg = input_port.recv();
} }
css_chan.send(CSSTaskExit); css_chan.send(CSSTaskExit);
@ -581,6 +597,7 @@ pub fn parse_html(cx: *JSContext,
HtmlParserResult { HtmlParserResult {
root: root, root: root,
discovery_port: discovery_port, discovery_port: discovery_port,
url: final_url,
} }
} }

View file

@ -702,7 +702,7 @@ impl ScriptTask {
page.next_subpage_id.clone(), page.next_subpage_id.clone(),
self.constellation_chan.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)); let document = HTMLDocument::new(root, Some(window));
@ -711,7 +711,7 @@ impl ScriptTask {
document: document, document: document,
window: window, window: window,
}); });
page.url = Some((url.clone(), true)); page.url = Some((final_url, true));
// Send style sheets over to layout. // Send style sheets over to layout.
// //