Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make resource requests cancelable (issue 4974) #5826

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -5,7 +5,7 @@
use net_traits::{LoadData, Metadata, LoadConsumer};
use net_traits::ProgressMsg::Done;
use mime_classifier::MIMEClassifier;
use resource_task::start_sending;
use resource_task::{start_sending, CancelationListener};
use file_loader;

use url::Url;
@@ -18,7 +18,7 @@ use std::borrow::IntoCow;
use std::fs::PathExt;
use std::sync::Arc;

pub fn factory(mut load_data: LoadData, start_chan: LoadConsumer, classifier: Arc<MIMEClassifier>) {
pub fn factory(mut load_data: LoadData, start_chan: LoadConsumer, classifier: Arc<MIMEClassifier>, cancel_receiver: CancelationListener) {
match load_data.url.non_relative_scheme_data().unwrap() {
"blank" => {
let chan = start_sending(start_chan, Metadata {
@@ -44,5 +44,5 @@ pub fn factory(mut load_data: LoadData, start_chan: LoadConsumer, classifier: Ar
return
}
};
file_loader::factory(load_data, start_chan, classifier)
file_loader::factory(load_data, start_chan, classifier, cancel_receiver)
}
@@ -5,23 +5,23 @@
use net_traits::{LoadData, Metadata, LoadConsumer};
use net_traits::ProgressMsg::{Payload, Done};
use mime_classifier::MIMEClassifier;
use resource_task::start_sending;
use resource_task::{start_sending, CancelationListener};

use rustc_serialize::base64::FromBase64;

use hyper::mime::Mime;
use std::sync::Arc;
use url::{percent_decode, SchemeData};

pub fn factory(load_data: LoadData, senders: LoadConsumer, _classifier: Arc<MIMEClassifier>) {
pub fn factory(load_data: LoadData, senders: LoadConsumer, _classifier: Arc<MIMEClassifier>, cancel_receiver: CancelationListener) {
// NB: we don't spawn a new task.
// Hypothesis: data URLs are too small for parallel base64 etc. to be worth it.
// Should be tested at some point.
// Left in separate function to allow easy moving to a task, if desired.
load(load_data, senders)
load(load_data, senders, cancel_receiver)
}

pub fn load(load_data: LoadData, start_chan: LoadConsumer) {
pub fn load(load_data: LoadData, start_chan: LoadConsumer, cancel_receiver: CancelationListener) {
let url = load_data.url;
assert!(&*url.scheme == "data");

@@ -45,6 +45,12 @@ pub fn load(load_data: LoadData, start_chan: LoadConsumer) {
return;
}

// Check that the request has not been cancelled,
// even though it is very unlikely to happen this soon
if cancel_receiver.is_cancelled() {
return;
}

// ";base64" must come at the end of the content type, per RFC 2397.
// rust-http will fail to parse it because there's no =value part.
let mut is_base64 = false;
@@ -5,7 +5,7 @@
use net_traits::{LoadData, Metadata, LoadConsumer};
use net_traits::ProgressMsg::{Payload, Done};
use mime_classifier::MIMEClassifier;
use resource_task::{start_sending, start_sending_sniffed, ProgressSender};
use resource_task::{start_sending, start_sending_sniffed, ProgressSender, CancelationListener};

use std::borrow::ToOwned;
use std::fs::File;
@@ -33,17 +33,27 @@ fn read_block(reader: &mut File) -> Result<ReadStatus, String> {
}
}

fn read_all(reader: &mut File, progress_chan: &ProgressSender)
-> Result<(), String> {
// returns true on cancelation, false on natural finish
fn read_all(reader: &mut File,
progress_chan: &ProgressSender,
cancel_receiver: &CancelationListener)
-> Result<bool, String> {
loop {
if cancel_receiver.is_cancelled() {
return Ok(true);
}

match try!(read_block(reader)) {
ReadStatus::Partial(buf) => progress_chan.send(Payload(buf)).unwrap(),
ReadStatus::EOF => return Ok(()),
ReadStatus::EOF => return Ok(false),
}
}
}

pub fn factory(load_data: LoadData, senders: LoadConsumer, classifier: Arc<MIMEClassifier>) {
pub fn factory(load_data: LoadData,
senders: LoadConsumer,
classifier: Arc<MIMEClassifier>,
cancel_receiver: CancelationListener) {
let url = load_data.url;
assert!(&*url.scheme == "file");
spawn_named("file_loader".to_owned(), move || {
@@ -53,13 +63,22 @@ pub fn factory(load_data: LoadData, senders: LoadConsumer, classifier: Arc<MIMEC
Ok(file_path) => {
match File::open(&file_path) {
Ok(ref mut reader) => {
if cancel_receiver.is_cancelled() {
return;
}
let res = read_block(reader);
let (res, progress_chan) = match res {
Ok(ReadStatus::Partial(buf)) => {
let progress_chan = start_sending_sniffed(senders, metadata,
classifier, &buf);
progress_chan.send(Payload(buf)).unwrap();
(read_all(reader, &progress_chan), progress_chan)

let read_result = read_all(reader, &progress_chan, &cancel_receiver);
if let Ok(true) = read_result {
return;
}

(read_result.map(|_| ()), progress_chan)
}
Ok(ReadStatus::EOF) | Err(_) =>
(res.map(|_| ()), start_sending(senders, metadata)),
@@ -5,7 +5,7 @@
use net_traits::{ControlMsg, CookieSource, LoadData, Metadata, LoadConsumer};
use net_traits::ProgressMsg::{Payload, Done};
use mime_classifier::MIMEClassifier;
use resource_task::{start_sending_opt, start_sending_sniffed_opt};
use resource_task::{start_sending_opt, start_sending_sniffed_opt, CancelationListener};

use log;
use std::collections::HashSet;
@@ -32,9 +32,9 @@ use url::{Url, UrlParser};
use std::borrow::ToOwned;

pub fn factory(cookies_chan: Sender<ControlMsg>)
-> Box<Invoke<(LoadData, LoadConsumer, Arc<MIMEClassifier>)> + Send> {
box move |(load_data, senders, classifier)| {
spawn_named("http_loader".to_owned(), move || load(load_data, senders, classifier, cookies_chan))
-> Box<Invoke<(LoadData, LoadConsumer, Arc<MIMEClassifier>, CancelationListener)> + Send> {
box move |(load_data, senders, classifier, cancel_receiver)| {
spawn_named("http_loader".to_owned(), move || load(load_data, senders, classifier, cookies_chan, cancel_receiver))
}
}

@@ -66,7 +66,8 @@ fn read_block<R: Read>(reader: &mut R) -> Result<ReadResult, ()> {
}
}

fn load(mut load_data: LoadData, start_chan: LoadConsumer, classifier: Arc<MIMEClassifier>, cookies_chan: Sender<ControlMsg>) {
fn load(mut load_data: LoadData, start_chan: LoadConsumer, classifier: Arc<MIMEClassifier>,
cookies_chan: Sender<ControlMsg>, cancel_receiver: CancelationListener) {
// FIXME: At the time of writing this FIXME, servo didn't have any central
// location for configuration. If you're reading this and such a
// repository DOES exist, please update this constant to use it.
@@ -140,7 +141,7 @@ reason: \"certificate verify failed\" }]";
let mut image = resources_dir_path();
image.push("badcert.html");
let load_data = LoadData::new(Url::from_file_path(&*image).unwrap());
file_loader::factory(load_data, start_chan, classifier);
file_loader::factory(load_data, start_chan, classifier, cancel_receiver);
return;
},
Err(e) => {
@@ -186,6 +187,10 @@ reason: \"certificate verify failed\" }]";
info!("{:?}", load_data.data);
}

if cancel_receiver.is_cancelled() {
return;
}

// Avoid automatically sending request body if a redirect has occurred.
let writer = match load_data.data {
Some(ref data) if iters == 1 => {
@@ -318,18 +323,31 @@ reason: \"certificate verify failed\" }]";
}
}

if cancel_receiver.is_cancelled() {
return;
}

match encoding_str {
Some(encoding) => {
if encoding == "gzip" {
let mut response_decoding = GzDecoder::new(response).unwrap();
send_data(&mut response_decoding, start_chan, metadata, classifier);
if send_data(&mut response_decoding, start_chan, metadata,
classifier, &cancel_receiver) {
return;
}
} else if encoding == "deflate" {
let mut response_decoding = DeflateDecoder::new(response);
send_data(&mut response_decoding, start_chan, metadata, classifier);
if send_data(&mut response_decoding, start_chan, metadata,
classifier, &cancel_receiver) {
return;
}
}
},
None => {
send_data(&mut response, start_chan, metadata, classifier);
if send_data(&mut response, start_chan, metadata,
classifier, &cancel_receiver) {
return;
}
}
}

@@ -341,25 +359,34 @@ reason: \"certificate verify failed\" }]";
fn send_data<R: Read>(reader: &mut R,
start_chan: LoadConsumer,
metadata: Metadata,
classifier: Arc<MIMEClassifier>) {
classifier: Arc<MIMEClassifier>,
cancel_receiver: &CancelationListener) -> bool {
if cancel_receiver.is_cancelled() {
return true;
}

let (progress_chan, mut chunk) = {
let buf = match read_block(reader) {
Ok(ReadResult::Payload(buf)) => buf,
_ => vec!(),
};
let p = match start_sending_sniffed_opt(start_chan, metadata, classifier, &buf) {
Ok(p) => p,
_ => return
_ => return false
};
(p, buf)
};

loop {
if cancel_receiver.is_cancelled() {
return true;
}

if progress_chan.send(Payload(chunk)).is_err() {
// The send errors when the receiver is out of scope,
// which will happen if the fetch has timed out (or has been aborted)
// so we don't need to continue with the loading of the file here.
return;
return false;
}

chunk = match read_block(reader) {
@@ -368,5 +395,11 @@ fn send_data<R: Read>(reader: &mut R,
};
}

if cancel_receiver.is_cancelled() {
return true;
}

let _ = progress_chan.send(Done(Ok(())));

false
}
@@ -311,7 +311,7 @@ impl ImageCache {
url: url,
sender: self.progress_sender.clone(),
};
self.resource_task.send(ControlMsg::Load(load_data, LoadConsumer::Listener(listener))).unwrap();
self.resource_task.send(ControlMsg::Load(load_data, LoadConsumer::Listener(listener), None)).unwrap();
}
}
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.