Auto merge of #6586 - pcwalton:resource-task-ipc, r=jdm

script: Make the resource task communication use IPC channels.

This change makes Servo use serialized messages over IPC channels for resource loading. The goal is to make it easier to make Servo multiprocess in the future. This patch does not make Servo multiprocess now; there are many other channels that need to be changed to IPC before that can happen. It does introduce a dependency on https://github.com/serde-rs/serde and https://github.com/pcwalton/ipc-channel for the first time.

At the moment, `ipc-channel` uses JSON for serialization. This is because serde does not yet have official support for bincode. When serde gains support for bincode, I'll switch to that. For now, however, the JSON encoding and decoding will constitute a significant performance regression in resource loading.

To avoid having to send boxed `AsyncResponseTarget` trait objects across process boundaries, this series of commits changes `AsyncResponseTarget` to wrap a sender only. It is then the client's responsibility to spawn a thread to proxy calls from that sender to the consumer of the resource data. This only had to be done in a few places. In the future, we may want to collapse those threads into one per process to reduce overhead. (It is impossible to continue to use `AsyncResponseTarget` as a boxed trait object across processes, regardless of how much work is done on `ipc-channel`. Vtables are fundamentally incompatible with IPC across mutually untrusting processes.)

In general, I was pretty pleased with how this turned out. The main changes are adding serialization functionality to various objects that `serde` does not know how to serialize natively—the most complicated being Hyper objects—and reworking `AsyncResponseTarget`. The overall structure of the code is unchanged, and other than `AsyncResponseTarget` no functionality was lost in moving to serialization and IPC.

r? @jdm

<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/6586)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2015-07-31 16:06:36 -06:00
commit 2eb122f394
36 changed files with 232 additions and 129 deletions

View file

@ -66,10 +66,13 @@ git = "https://github.com/pcwalton/ipc-channel"
git = "https://github.com/ecoal95/rust-offscreen-rendering-context" git = "https://github.com/ecoal95/rust-offscreen-rendering-context"
features = ["texture_surface"] features = ["texture_surface"]
[dependencies.url]
version = "0.2"
features = [ "serde_serialization" ]
[dependencies] [dependencies]
log = "0.3" log = "0.3"
num = "0.1.24" num = "0.1.24"
url = "0.2.36"
time = "0.1.17" time = "0.1.17"
libc = "0.1" libc = "0.1"
gleam = "0.1" gleam = "0.1"
@ -80,3 +83,4 @@ core-graphics = "0.1"
[target.x86_64-apple-darwin.dependencies.core-text] [target.x86_64-apple-darwin.dependencies.core-text]
git = "https://github.com/servo/core-text-rs" git = "https://github.com/servo/core-text-rs"

View file

@ -47,10 +47,13 @@ path = "../script_traits"
[dependencies.ipc-channel] [dependencies.ipc-channel]
git = "https://github.com/pcwalton/ipc-channel" git = "https://github.com/pcwalton/ipc-channel"
[dependencies.url]
version = "0.2"
features = [ "serde_serialization" ]
[dependencies] [dependencies]
log = "0.3" log = "0.3"
fnv = "1.0" fnv = "1.0"
url = "0.2.36"
time = "0.1.12" time = "0.1.12"
bitflags = "0.3" bitflags = "0.3"
rustc-serialize = "0.3" rustc-serialize = "0.3"

View file

@ -62,11 +62,14 @@ features = [ "serde-serialization" ]
[dependencies.ipc-channel] [dependencies.ipc-channel]
git = "https://github.com/pcwalton/ipc-channel" git = "https://github.com/pcwalton/ipc-channel"
[dependencies.url]
version = "0.2"
features = [ "serde_serialization" ]
[dependencies] [dependencies]
log = "0.3" log = "0.3"
encoding = "0.2" encoding = "0.2"
fnv = "1.0" fnv = "1.0"
url = "0.2.36"
bitflags = "0.3" bitflags = "0.3"
rustc-serialize = "0.3" rustc-serialize = "0.3"
libc = "0.1" libc = "0.1"

View file

@ -28,8 +28,11 @@ path = "../util"
[dependencies.ipc-channel] [dependencies.ipc-channel]
git = "https://github.com/pcwalton/ipc-channel" git = "https://github.com/pcwalton/ipc-channel"
[dependencies.url]
version = "0.2"
features = [ "serde_serialization" ]
[dependencies] [dependencies]
url = "0.2.36"
euclid = "0.1" euclid = "0.1"
serde = "0.4" serde = "0.4"
serde_macros = "0.4" serde_macros = "0.4"

View file

@ -27,9 +27,12 @@ features = [ "serde-serialization" ]
[dependencies.ipc-channel] [dependencies.ipc-channel]
git = "https://github.com/pcwalton/ipc-channel" git = "https://github.com/pcwalton/ipc-channel"
[dependencies.url]
version = "0.2"
features = [ "serde_serialization" ]
[dependencies] [dependencies]
log = "0.3" log = "0.3"
url = "0.2.36"
time = "0.1.17" time = "0.1.17"
openssl="0.6.1" openssl="0.6.1"
rustc-serialize = "0.3" rustc-serialize = "0.3"
@ -39,3 +42,4 @@ regex_macros = "0.1.8"
flate2 = "0.2.0" flate2 = "0.2.0"
uuid = "0.1.16" uuid = "0.1.16"
euclid = "0.1" euclid = "0.1"

View file

@ -39,7 +39,8 @@ pub fn factory(mut load_data: LoadData, start_chan: LoadConsumer, classifier: Ar
} }
_ => { _ => {
start_sending(start_chan, Metadata::default(load_data.url)) start_sending(start_chan, Metadata::default(load_data.url))
.send(Done(Err("Unknown about: URL.".to_string()))).unwrap(); .send(Done(Err("Unknown about: URL.".to_string())))
.unwrap();
return return
} }
}; };

View file

@ -34,15 +34,16 @@ pub fn load(load_data: LoadData, start_chan: LoadConsumer) {
_ => panic!("Expected a non-relative scheme URL.") _ => panic!("Expected a non-relative scheme URL.")
}; };
match url.query { match url.query {
Some(query) => { Some(ref query) => {
scheme_data.push_str("?"); scheme_data.push_str("?");
scheme_data.push_str(&query); scheme_data.push_str(query);
}, },
None => () None => ()
} }
let parts: Vec<&str> = scheme_data.splitn(2, ',').collect(); let parts: Vec<&str> = scheme_data.splitn(2, ',').collect();
if parts.len() != 2 { if parts.len() != 2 {
start_sending(start_chan, metadata).send(Done(Err("invalid data uri".to_string()))).unwrap(); start_sending(start_chan,
metadata).send(Done(Err("invalid data uri".to_string()))).unwrap();
return; return;
} }

View file

@ -9,6 +9,7 @@ use mime_classifier::MIMEClassifier;
use resource_task::{start_sending_opt, start_sending_sniffed_opt}; use resource_task::{start_sending_opt, start_sending_sniffed_opt};
use hsts::{HSTSList, secure_url}; use hsts::{HSTSList, secure_url};
use ipc_channel::ipc::{self, IpcSender};
use log; use log;
use std::collections::HashSet; use std::collections::HashSet;
use file_loader; use file_loader;
@ -36,7 +37,7 @@ use uuid;
use std::borrow::ToOwned; use std::borrow::ToOwned;
use std::boxed::FnBox; use std::boxed::FnBox;
pub fn factory(cookies_chan: Sender<ControlMsg>, pub fn factory(cookies_chan: IpcSender<ControlMsg>,
devtools_chan: Option<Sender<DevtoolsControlMsg>>, devtools_chan: Option<Sender<DevtoolsControlMsg>>,
hsts_list: Arc<Mutex<HSTSList>>) hsts_list: Arc<Mutex<HSTSList>>)
-> Box<FnBox(LoadData, LoadConsumer, Arc<MIMEClassifier>) + Send> { -> Box<FnBox(LoadData, LoadConsumer, Arc<MIMEClassifier>) + Send> {
@ -86,7 +87,7 @@ fn request_must_be_secured(hsts_list: &HSTSList, url: &Url) -> bool {
fn load(mut load_data: LoadData, fn load(mut load_data: LoadData,
start_chan: LoadConsumer, start_chan: LoadConsumer,
classifier: Arc<MIMEClassifier>, classifier: Arc<MIMEClassifier>,
cookies_chan: Sender<ControlMsg>, cookies_chan: IpcSender<ControlMsg>,
devtools_chan: Option<Sender<DevtoolsControlMsg>>, devtools_chan: Option<Sender<DevtoolsControlMsg>>,
hsts_list: Arc<Mutex<HSTSList>>) { hsts_list: Arc<Mutex<HSTSList>>) {
// FIXME: At the time of writing this FIXME, servo didn't have any central // FIXME: At the time of writing this FIXME, servo didn't have any central
@ -153,6 +154,7 @@ reason: \"certificate verify failed\" }]))";
Request::with_connector(load_data.method.clone(), url.clone(), Request::with_connector(load_data.method.clone(), url.clone(),
&HttpsConnector::new(Openssl { context: Arc::new(context) })) &HttpsConnector::new(Openssl { context: Arc::new(context) }))
}; };
let mut req = match req { let mut req = match req {
Ok(req) => req, Ok(req) => req,
Err(HttpError::Io(ref io_error)) if ( Err(HttpError::Io(ref io_error)) if (
@ -201,8 +203,10 @@ reason: \"certificate verify failed\" }]))";
req.headers_mut().set(accept); req.headers_mut().set(accept);
} }
let (tx, rx) = channel(); let (tx, rx) = ipc::channel().unwrap();
cookies_chan.send(ControlMsg::GetCookiesForUrl(url.clone(), tx, CookieSource::HTTP)).unwrap(); cookies_chan.send(ControlMsg::GetCookiesForUrl(url.clone(),
tx,
CookieSource::HTTP)).unwrap();
if let Some(cookie_list) = rx.recv().unwrap() { if let Some(cookie_list) = rx.recv().unwrap() {
let mut v = Vec::new(); let mut v = Vec::new();
v.push(cookie_list.into_bytes()); v.push(cookie_list.into_bytes());

View file

@ -97,20 +97,6 @@ struct ResourceLoadInfo {
url: Url, url: Url,
} }
struct ResourceListener {
url: Url,
sender: Sender<ResourceLoadInfo>,
}
impl AsyncResponseTarget for ResourceListener {
fn invoke_with_listener(&self, action: ResponseAction) {
self.sender.send(ResourceLoadInfo {
action: action,
url: self.url.clone(),
}).unwrap();
}
}
/// Implementation of the image cache /// Implementation of the image cache
struct ImageCache { struct ImageCache {
// Receive commands from clients // Receive commands from clients
@ -330,11 +316,20 @@ impl ImageCache {
e.insert(pending_load); e.insert(pending_load);
let load_data = LoadData::new(url.clone(), None); let load_data = LoadData::new(url.clone(), None);
let listener = box ResourceListener { let (action_sender, action_receiver) = ipc::channel().unwrap();
url: url, let response_target = AsyncResponseTarget {
sender: self.progress_sender.clone(), sender: action_sender,
}; };
let msg = ControlMsg::Load(load_data, LoadConsumer::Listener(listener)); let msg = ControlMsg::Load(load_data,
LoadConsumer::Listener(response_target));
let progress_sender = self.progress_sender.clone();
ROUTER.add_route(action_receiver.to_opaque(), box move |message| {
let action: ResponseAction = message.to().unwrap();
progress_sender.send(ResourceLoadInfo {
action: action,
url: url.clone(),
}).unwrap();
});
self.resource_task.send(msg).unwrap(); self.resource_task.send(msg).unwrap();
} }
} }

View file

@ -12,8 +12,8 @@ use cookie_storage::CookieStorage;
use cookie; use cookie;
use mime_classifier::MIMEClassifier; use mime_classifier::MIMEClassifier;
use net_traits::{ControlMsg, LoadData, LoadResponse, LoadConsumer}; use net_traits::{ControlMsg, LoadData, LoadResponse, LoadConsumer, CookieSource};
use net_traits::{Metadata, ProgressMsg, ResourceTask, AsyncResponseTarget, ResponseAction, CookieSource}; use net_traits::{Metadata, ProgressMsg, ResourceTask, AsyncResponseTarget, ResponseAction};
use net_traits::ProgressMsg::Done; use net_traits::ProgressMsg::Done;
use util::opts; use util::opts;
use util::task::spawn_named; use util::task::spawn_named;
@ -24,6 +24,7 @@ use hsts::{HSTSList, HSTSEntry, preload_hsts_domains};
use devtools_traits::{DevtoolsControlMsg}; use devtools_traits::{DevtoolsControlMsg};
use hyper::header::{ContentType, Header, SetCookie, UserAgent}; use hyper::header::{ContentType, Header, SetCookie, UserAgent};
use hyper::mime::{Mime, TopLevel, SubLevel}; use hyper::mime::{Mime, TopLevel, SubLevel};
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use regex::Regex; use regex::Regex;
use std::borrow::ToOwned; use std::borrow::ToOwned;
@ -34,7 +35,7 @@ use std::fs::File;
use std::io::{BufReader, Read}; use std::io::{BufReader, Read};
use std::sync::Arc; use std::sync::Arc;
use std::sync::Mutex; use std::sync::Mutex;
use std::sync::mpsc::{channel, Receiver, Sender}; use std::sync::mpsc::{channel, Sender};
static mut HOST_TABLE: Option<*mut HashMap<String, String>> = None; static mut HOST_TABLE: Option<*mut HashMap<String, String>> = None;
pub static IPV4_REGEX: Regex = regex!( pub static IPV4_REGEX: Regex = regex!(
@ -67,8 +68,8 @@ pub fn global_init() {
} }
pub enum ProgressSender { pub enum ProgressSender {
Channel(Sender<ProgressMsg>), Channel(IpcSender<ProgressMsg>),
Listener(Box<AsyncResponseTarget>), Listener(AsyncResponseTarget),
} }
impl ProgressSender { impl ProgressSender {
@ -124,7 +125,8 @@ pub fn start_sending_sniffed_opt(start_chan: LoadConsumer, mut metadata: Metadat
} }
} }
let supplied_type = metadata.content_type.map(|ContentType(Mime(toplevel, sublevel, _))| { let supplied_type =
metadata.content_type.map(|ContentType(Mime(toplevel, sublevel, _))| {
(format!("{}", toplevel), format!("{}", sublevel)) (format!("{}", toplevel), format!("{}", sublevel))
}); });
metadata.content_type = classifier.classify(nosniff, check_for_apache_bug, &supplied_type, metadata.content_type = classifier.classify(nosniff, check_for_apache_bug, &supplied_type,
@ -143,7 +145,7 @@ pub fn start_sending_sniffed_opt(start_chan: LoadConsumer, mut metadata: Metadat
pub fn start_sending_opt(start_chan: LoadConsumer, metadata: Metadata) -> Result<ProgressSender, ()> { pub fn start_sending_opt(start_chan: LoadConsumer, metadata: Metadata) -> Result<ProgressSender, ()> {
match start_chan { match start_chan {
LoadConsumer::Channel(start_chan) => { LoadConsumer::Channel(start_chan) => {
let (progress_chan, progress_port) = channel(); let (progress_chan, progress_port) = ipc::channel().unwrap();
let result = start_chan.send(LoadResponse { let result = start_chan.send(LoadResponse {
metadata: metadata, metadata: metadata,
progress_port: progress_port, progress_port: progress_port,
@ -168,7 +170,7 @@ pub fn new_resource_task(user_agent: Option<String>,
None => HSTSList::new() None => HSTSList::new()
}; };
let (setup_chan, setup_port) = channel(); let (setup_chan, setup_port) = ipc::channel().unwrap();
let setup_chan_clone = setup_chan.clone(); let setup_chan_clone = setup_chan.clone();
spawn_named("ResourceManager".to_owned(), move || { spawn_named("ResourceManager".to_owned(), move || {
let resource_manager = ResourceManager::new( let resource_manager = ResourceManager::new(
@ -218,7 +220,7 @@ pub fn replace_hosts(mut load_data: LoadData, host_table: *mut HashMap<String, S
} }
struct ResourceChannelManager { struct ResourceChannelManager {
from_client: Receiver<ControlMsg>, from_client: IpcReceiver<ControlMsg>,
resource_manager: ResourceManager resource_manager: ResourceManager
} }
@ -251,8 +253,7 @@ impl ResourceChannelManager {
pub struct ResourceManager { pub struct ResourceManager {
user_agent: Option<String>, user_agent: Option<String>,
cookie_storage: CookieStorage, cookie_storage: CookieStorage,
// TODO: Can this be de-coupled? resource_task: IpcSender<ControlMsg>,
resource_task: Sender<ControlMsg>,
mime_classifier: Arc<MIMEClassifier>, mime_classifier: Arc<MIMEClassifier>,
devtools_chan: Option<Sender<DevtoolsControlMsg>>, devtools_chan: Option<Sender<DevtoolsControlMsg>>,
hsts_list: Arc<Mutex<HSTSList>> hsts_list: Arc<Mutex<HSTSList>>
@ -260,9 +261,9 @@ pub struct ResourceManager {
impl ResourceManager { impl ResourceManager {
pub fn new(user_agent: Option<String>, pub fn new(user_agent: Option<String>,
resource_task: Sender<ControlMsg>, resource_task: IpcSender<ControlMsg>,
hsts_list: HSTSList, hsts_list: HSTSList,
devtools_channel: Option<Sender<DevtoolsControlMsg>>) -> ResourceManager { devtools_channel: Option<Sender<DevtoolsControlMsg>>) -> ResourceManager {
ResourceManager { ResourceManager {
user_agent: user_agent, user_agent: user_agent,
cookie_storage: CookieStorage::new(), cookie_storage: CookieStorage::new(),
@ -274,7 +275,6 @@ impl ResourceManager {
} }
} }
impl ResourceManager { impl ResourceManager {
fn set_cookies_for_url(&mut self, request: Url, cookie_list: String, source: CookieSource) { fn set_cookies_for_url(&mut self, request: Url, cookie_list: String, source: CookieSource) {
let header = Header::parse_header(&[cookie_list.into_bytes()]); let header = Header::parse_header(&[cookie_list.into_bytes()]);

View file

@ -24,13 +24,13 @@ git = "https://github.com/servo/rust-stb-image"
version = "0.6" version = "0.6"
features = [ "serde-serialization" ] features = [ "serde-serialization" ]
[dependencies.url]
version = "0.2.36"
features = [ "serde_serialization" ]
[dependencies.ipc-channel] [dependencies.ipc-channel]
git = "https://github.com/pcwalton/ipc-channel" git = "https://github.com/pcwalton/ipc-channel"
[dependencies.url]
version = "0.2"
features = [ "serde_serialization" ]
[dependencies] [dependencies]
log = "0.3" log = "0.3"
euclid = "0.1" euclid = "0.1"

View file

@ -10,8 +10,6 @@
#![feature(vec_push_all)] #![feature(vec_push_all)]
#![plugin(serde_macros)] #![plugin(serde_macros)]
#![plugin(serde_macros)]
extern crate euclid; extern crate euclid;
extern crate hyper; extern crate hyper;
extern crate ipc_channel; extern crate ipc_channel;
@ -28,10 +26,11 @@ use hyper::header::{ContentType, Headers};
use hyper::http::RawStatus; use hyper::http::RawStatus;
use hyper::method::Method; use hyper::method::Method;
use hyper::mime::{Mime, Attr}; use hyper::mime::{Mime, Attr};
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use msg::constellation_msg::{PipelineId}; use msg::constellation_msg::{PipelineId};
use serde::{Deserializer, Serializer};
use url::Url; use url::Url;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread; use std::thread;
pub mod image_cache_task; pub mod image_cache_task;
@ -46,7 +45,7 @@ pub mod image {
pub mod base; pub mod base;
} }
#[derive(Clone)] #[derive(Clone, Deserialize, Serialize)]
pub struct LoadData { pub struct LoadData {
pub url: Url, pub url: Url,
pub method: Method, pub method: Method,
@ -87,6 +86,7 @@ pub trait AsyncResponseListener {
/// Data for passing between threads/processes to indicate a particular action to /// Data for passing between threads/processes to indicate a particular action to
/// take on a provided network listener. /// take on a provided network listener.
#[derive(Deserialize, Serialize)]
pub enum ResponseAction { pub enum ResponseAction {
/// Invoke headers_available /// Invoke headers_available
HeadersAvailable(Metadata), HeadersAvailable(Metadata),
@ -109,32 +109,41 @@ impl ResponseAction {
/// A target for async networking events. Commonly used to dispatch a runnable event to another /// A target for async networking events. Commonly used to dispatch a runnable event to another
/// thread storing the wrapped closure for later execution. /// thread storing the wrapped closure for later execution.
pub trait AsyncResponseTarget { #[derive(Deserialize, Serialize)]
fn invoke_with_listener(&self, action: ResponseAction); pub struct AsyncResponseTarget {
pub sender: IpcSender<ResponseAction>,
}
impl AsyncResponseTarget {
pub fn invoke_with_listener(&self, action: ResponseAction) {
self.sender.send(action).unwrap()
}
} }
/// A wrapper for a network load that can either be channel or event-based. /// A wrapper for a network load that can either be channel or event-based.
#[derive(Deserialize, Serialize)]
pub enum LoadConsumer { pub enum LoadConsumer {
Channel(Sender<LoadResponse>), Channel(IpcSender<LoadResponse>),
Listener(Box<AsyncResponseTarget + Send>), Listener(AsyncResponseTarget),
} }
/// Handle to a resource task /// Handle to a resource task
pub type ResourceTask = Sender<ControlMsg>; pub type ResourceTask = IpcSender<ControlMsg>;
#[derive(PartialEq, Copy, Clone)] #[derive(PartialEq, Copy, Clone, Deserialize, Serialize)]
pub enum IncludeSubdomains { pub enum IncludeSubdomains {
Included, Included,
NotIncluded NotIncluded
} }
#[derive(Deserialize, Serialize)]
pub enum ControlMsg { pub enum ControlMsg {
/// Request the data associated with a particular URL /// Request the data associated with a particular URL
Load(LoadData, LoadConsumer), Load(LoadData, LoadConsumer),
/// Store a set of cookies for a given originating URL /// Store a set of cookies for a given originating URL
SetCookiesForUrl(Url, String, CookieSource), SetCookiesForUrl(Url, String, CookieSource),
/// Retrieve the stored cookies for a given URL /// Retrieve the stored cookies for a given URL
GetCookiesForUrl(Url, Sender<Option<String>>, CookieSource), GetCookiesForUrl(Url, IpcSender<Option<String>>, CookieSource),
/// Store a domain's STS information /// Store a domain's STS information
SetHSTSEntryForHost(String, IncludeSubdomains, Option<u64>), SetHSTSEntryForHost(String, IncludeSubdomains, Option<u64>),
Exit Exit
@ -180,17 +189,17 @@ impl PendingAsyncLoad {
} }
/// Initiate the network request associated with this pending load. /// Initiate the network request associated with this pending load.
pub fn load(mut self) -> Receiver<LoadResponse> { pub fn load(mut self) -> IpcReceiver<LoadResponse> {
self.guard.neuter(); self.guard.neuter();
let load_data = LoadData::new(self.url, self.pipeline); let load_data = LoadData::new(self.url, self.pipeline);
let (sender, receiver) = channel(); let (sender, receiver) = ipc::channel().unwrap();
let consumer = LoadConsumer::Channel(sender); let consumer = LoadConsumer::Channel(sender);
self.resource_task.send(ControlMsg::Load(load_data, consumer)).unwrap(); self.resource_task.send(ControlMsg::Load(load_data, consumer)).unwrap();
receiver receiver
} }
/// Initiate the network request associated with this pending load, using the provided target. /// Initiate the network request associated with this pending load, using the provided target.
pub fn load_async(mut self, listener: Box<AsyncResponseTarget + Send>) { pub fn load_async(mut self, listener: AsyncResponseTarget) {
self.guard.neuter(); self.guard.neuter();
let load_data = LoadData::new(self.url, self.pipeline); let load_data = LoadData::new(self.url, self.pipeline);
let consumer = LoadConsumer::Listener(listener); let consumer = LoadConsumer::Listener(listener);
@ -203,23 +212,24 @@ impl PendingAsyncLoad {
/// ///
/// Even if loading fails immediately, we send one of these and the /// Even if loading fails immediately, we send one of these and the
/// progress_port will provide the error. /// progress_port will provide the error.
#[derive(Serialize, Deserialize)]
pub struct LoadResponse { pub struct LoadResponse {
/// Metadata, such as from HTTP headers. /// Metadata, such as from HTTP headers.
pub metadata: Metadata, pub metadata: Metadata,
/// Port for reading data. /// Port for reading data.
pub progress_port: Receiver<ProgressMsg>, pub progress_port: IpcReceiver<ProgressMsg>,
} }
#[derive(Clone)] #[derive(Clone, Deserialize, Serialize)]
pub struct ResourceCORSData { pub struct ResourceCORSData {
/// CORS Preflight flag /// CORS Preflight flag
pub preflight: bool, pub preflight: bool,
/// Origin of CORS Request /// Origin of CORS Request
pub origin: Url pub origin: Url,
} }
/// Metadata about a loaded resource, such as is obtained from HTTP headers. /// Metadata about a loaded resource, such as is obtained from HTTP headers.
#[derive(Clone)] #[derive(Clone, Deserialize, Serialize)]
pub struct Metadata { pub struct Metadata {
/// Final URL after redirects. /// Final URL after redirects.
pub final_url: Url, pub final_url: Url,
@ -268,7 +278,7 @@ impl Metadata {
} }
/// The creator of a given cookie /// The creator of a given cookie
#[derive(PartialEq, Copy, Clone)] #[derive(PartialEq, Copy, Clone, Deserialize, Serialize)]
pub enum CookieSource { pub enum CookieSource {
/// An HTTP API /// An HTTP API
HTTP, HTTP,
@ -277,7 +287,7 @@ pub enum CookieSource {
} }
/// Messages sent in response to a `Load` message /// Messages sent in response to a `Load` message
#[derive(PartialEq,Debug)] #[derive(PartialEq, Debug, Deserialize, Serialize)]
pub enum ProgressMsg { pub enum ProgressMsg {
/// Binary data - there may be multiple of these /// Binary data - there may be multiple of these
Payload(Vec<u8>), Payload(Vec<u8>),
@ -288,16 +298,17 @@ pub enum ProgressMsg {
/// Convenience function for synchronously loading a whole resource. /// Convenience function for synchronously loading a whole resource.
pub fn load_whole_resource(resource_task: &ResourceTask, url: Url) pub fn load_whole_resource(resource_task: &ResourceTask, url: Url)
-> Result<(Metadata, Vec<u8>), String> { -> Result<(Metadata, Vec<u8>), String> {
let (start_chan, start_port) = channel(); let (start_chan, start_port) = ipc::channel().unwrap();
resource_task.send(ControlMsg::Load(LoadData::new(url, None), LoadConsumer::Channel(start_chan))).unwrap(); resource_task.send(ControlMsg::Load(LoadData::new(url, None),
LoadConsumer::Channel(start_chan))).unwrap();
let response = start_port.recv().unwrap(); let response = start_port.recv().unwrap();
let mut buf = vec!(); let mut buf = vec!();
loop { loop {
match response.progress_port.recv().unwrap() { match response.progress_port.recv().unwrap() {
ProgressMsg::Payload(data) => buf.push_all(&data), ProgressMsg::Payload(data) => buf.push_all(&data),
ProgressMsg::Done(Ok(())) => return Ok((response.metadata, buf)), ProgressMsg::Done(Ok(())) => return Ok((response.metadata, buf)),
ProgressMsg::Done(Err(e)) => return Err(e) ProgressMsg::Done(Err(e)) => return Err(e)
} }
} }
} }
@ -306,13 +317,15 @@ pub fn load_whole_resource(resource_task: &ResourceTask, url: Url)
pub fn load_bytes_iter(pending: PendingAsyncLoad) -> (Metadata, ProgressMsgPortIterator) { pub fn load_bytes_iter(pending: PendingAsyncLoad) -> (Metadata, ProgressMsgPortIterator) {
let input_port = pending.load(); let input_port = pending.load();
let response = input_port.recv().unwrap(); let response = input_port.recv().unwrap();
let iter = ProgressMsgPortIterator { progress_port: response.progress_port }; let iter = ProgressMsgPortIterator {
progress_port: response.progress_port
};
(response.metadata, iter) (response.metadata, iter)
} }
/// Iterator that reads chunks of bytes from a ProgressMsg port /// Iterator that reads chunks of bytes from a ProgressMsg port
pub struct ProgressMsgPortIterator { pub struct ProgressMsgPortIterator {
progress_port: Receiver<ProgressMsg> progress_port: IpcReceiver<ProgressMsg>,
} }
impl Iterator for ProgressMsgPortIterator { impl Iterator for ProgressMsgPortIterator {
@ -330,4 +343,3 @@ impl Iterator for ProgressMsgPortIterator {
} }
} }

View file

@ -10,9 +10,12 @@ path = "lib.rs"
[dependencies.ipc-channel] [dependencies.ipc-channel]
git = "https://github.com/pcwalton/ipc-channel" git = "https://github.com/pcwalton/ipc-channel"
[dependencies.url]
version = "0.2"
features = [ "serde_serialization" ]
[dependencies] [dependencies]
serde = "0.4" serde = "0.4"
serde_macros = "0.4" serde_macros = "0.4"
time = "0.1.12" time = "0.1.12"
url = "0.2.36"

View file

@ -76,7 +76,7 @@ rustc-serialize = "0.3"
libc = "0.1" libc = "0.1"
unicase = "0.1" unicase = "0.1"
num = "0.1.24" num = "0.1.24"
websocket = "0.12" websocket = "0.12.0"
uuid = "0.1.16" uuid = "0.1.16"
smallvec = "0.1" smallvec = "0.1"
html5ever = { version = "0.2.1", features = ["unstable"] } html5ever = { version = "0.2.1", features = ["unstable"] }

View file

@ -11,7 +11,7 @@
use network_listener::{NetworkListener, PreInvoke}; use network_listener::{NetworkListener, PreInvoke};
use script_task::ScriptChan; use script_task::ScriptChan;
use net_traits::{AsyncResponseTarget, AsyncResponseListener, ResponseAction, Metadata}; use net_traits::{AsyncResponseListener, ResponseAction, Metadata};
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::borrow::ToOwned; use std::borrow::ToOwned;
@ -144,7 +144,7 @@ impl CORSRequest {
let mut context = listener.context.lock(); let mut context = listener.context.lock();
let context = context.as_mut().unwrap(); let context = context.as_mut().unwrap();
*context.response.borrow_mut() = Some(response); *context.response.borrow_mut() = Some(response);
listener.invoke_with_listener(ResponseAction::ResponseComplete(Ok(()))); listener.notify(ResponseAction::ResponseComplete(Ok(())));
}); });
} }

View file

@ -9,6 +9,7 @@ use script_task::{ScriptMsg, ScriptChan};
use msg::constellation_msg::{PipelineId}; use msg::constellation_msg::{PipelineId};
use net_traits::{Metadata, load_whole_resource, ResourceTask, PendingAsyncLoad}; use net_traits::{Metadata, load_whole_resource, ResourceTask, PendingAsyncLoad};
use net_traits::AsyncResponseTarget; use net_traits::AsyncResponseTarget;
use std::sync::Arc;
use url::Url; use url::Url;
#[derive(JSTraceable, PartialEq, Clone, Debug)] #[derive(JSTraceable, PartialEq, Clone, Debug)]
@ -34,7 +35,9 @@ impl LoadType {
#[derive(JSTraceable)] #[derive(JSTraceable)]
pub struct DocumentLoader { pub struct DocumentLoader {
pub resource_task: ResourceTask, /// We use an `Arc<ResourceTask>` here in order to avoid file descriptor exhaustion when there
/// are lots of iframes.
pub resource_task: Arc<ResourceTask>,
notifier_data: Option<NotifierData>, notifier_data: Option<NotifierData>,
blocking_loads: Vec<LoadType>, blocking_loads: Vec<LoadType>,
} }
@ -50,7 +53,9 @@ impl DocumentLoader {
DocumentLoader::new_with_task(existing.resource_task.clone(), None, None) DocumentLoader::new_with_task(existing.resource_task.clone(), None, None)
} }
pub fn new_with_task(resource_task: ResourceTask, /// We use an `Arc<ResourceTask>` here in order to avoid file descriptor exhaustion when there
/// are lots of iframes.
pub fn new_with_task(resource_task: Arc<ResourceTask>,
data: Option<NotifierData>, data: Option<NotifierData>,
initial_load: Option<Url>,) initial_load: Option<Url>,)
-> DocumentLoader { -> DocumentLoader {
@ -69,11 +74,11 @@ impl DocumentLoader {
let url = load.url().clone(); let url = load.url().clone();
self.blocking_loads.push(load); self.blocking_loads.push(load);
let pipeline = self.notifier_data.as_ref().map(|data| data.pipeline); let pipeline = self.notifier_data.as_ref().map(|data| data.pipeline);
PendingAsyncLoad::new(self.resource_task.clone(), url, pipeline) PendingAsyncLoad::new((*self.resource_task).clone(), url, pipeline)
} }
/// Create and initiate a new network request. /// Create and initiate a new network request.
pub fn load_async(&mut self, load: LoadType, listener: Box<AsyncResponseTarget + Send>) { pub fn load_async(&mut self, load: LoadType, listener: AsyncResponseTarget) {
let pending = self.prepare_async_load(load); let pending = self.prepare_async_load(load);
pending.load_async(listener) pending.load_async(listener)
} }

View file

@ -116,7 +116,7 @@ impl<'a> GlobalRef<'a> {
let doc = window.Document(); let doc = window.Document();
let doc = doc.r(); let doc = doc.r();
let loader = doc.loader(); let loader = doc.loader();
loader.resource_task.clone() (*loader.resource_task).clone()
} }
GlobalRef::Worker(ref worker) => worker.resource_task().clone(), GlobalRef::Worker(ref worker) => worker.resource_task().clone(),
} }

View file

@ -45,7 +45,7 @@ use euclid::size::Size2D;
use html5ever::tree_builder::QuirksMode; use html5ever::tree_builder::QuirksMode;
use hyper::header::Headers; use hyper::header::Headers;
use hyper::method::Method; use hyper::method::Method;
use ipc_channel::ipc::IpcSender; use ipc_channel::ipc::{IpcReceiver, IpcSender};
use js::jsapi::{JSObject, JSTracer, JSGCTraceKind, JS_CallValueTracer, JS_CallObjectTracer, GCTraceKindToAscii, Heap}; use js::jsapi::{JSObject, JSTracer, JSGCTraceKind, JS_CallValueTracer, JS_CallObjectTracer, GCTraceKindToAscii, Heap};
use js::jsapi::JS_CallUnbarrieredObjectTracer; use js::jsapi::JS_CallUnbarrieredObjectTracer;
use js::jsval::JSVal; use js::jsval::JSVal;
@ -57,6 +57,7 @@ use net_traits::image_cache_task::{ImageCacheChan, ImageCacheTask};
use net_traits::storage_task::StorageType; use net_traits::storage_task::StorageType;
use script_traits::ScriptControlChan; use script_traits::ScriptControlChan;
use script_traits::UntrustedNodeAddress; use script_traits::UntrustedNodeAddress;
use serde::{Serialize, Deserialize};
use smallvec::SmallVec; use smallvec::SmallVec;
use msg::compositor_msg::ScriptListener; use msg::compositor_msg::ScriptListener;
use msg::constellation_msg::ConstellationChan; use msg::constellation_msg::ConstellationChan;
@ -64,7 +65,6 @@ use net_traits::image::base::Image;
use profile_traits::mem::ProfilerChan; use profile_traits::mem::ProfilerChan;
use util::str::{LengthOrPercentageOrAuto}; use util::str::{LengthOrPercentageOrAuto};
use selectors::parser::PseudoElement; use selectors::parser::PseudoElement;
use serde::{Deserialize, Serialize};
use std::cell::{Cell, UnsafeCell, RefCell}; use std::cell::{Cell, UnsafeCell, RefCell};
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::collections::hash_state::HashState; use std::collections::hash_state::HashState;
@ -358,7 +358,15 @@ impl JSTraceable for Box<LayoutRPC+'static> {
impl JSTraceable for () { impl JSTraceable for () {
#[inline] #[inline]
fn trace(&self, _trc: *mut JSTracer) { fn trace(&self, _: *mut JSTracer) {
// Do nothing
}
}
impl<T> JSTraceable for IpcReceiver<T> where T: Deserialize + Serialize {
#[inline]
fn trace(&self, _: *mut JSTracer) {
// Do nothing
} }
} }

View file

@ -181,8 +181,8 @@ impl DedicatedWorkerGlobalScope {
let serialized_url = url.serialize(); let serialized_url = url.serialize();
let parent_sender_for_reporter = parent_sender.clone(); let parent_sender_for_reporter = parent_sender.clone();
let global = DedicatedWorkerGlobalScope::new( let global = DedicatedWorkerGlobalScope::new(
url, id, mem_profiler_chan.clone(), devtools_chan, runtime.clone(), resource_task, url, id, mem_profiler_chan.clone(), devtools_chan, runtime.clone(),
constellation_chan, parent_sender, own_sender, receiver); resource_task, constellation_chan, parent_sender, own_sender, receiver);
// FIXME(njn): workers currently don't have a unique ID suitable for using in reporter // FIXME(njn): workers currently don't have a unique ID suitable for using in reporter
// registration (#6631), so we instead use a random number and cross our fingers. // registration (#6631), so we instead use a random number and cross our fingers.
let reporter_name = format!("worker-reporter-{}", random::<u64>()); let reporter_name = format!("worker-reporter-{}", random::<u64>());

View file

@ -83,6 +83,7 @@ use layout_interface::{ReflowGoal, ReflowQueryType};
use euclid::point::Point2D; use euclid::point::Point2D;
use html5ever::tree_builder::{QuirksMode, NoQuirks, LimitedQuirks, Quirks}; use html5ever::tree_builder::{QuirksMode, NoQuirks, LimitedQuirks, Quirks};
use ipc_channel::ipc;
use layout_interface::{LayoutChan, Msg}; use layout_interface::{LayoutChan, Msg};
use string_cache::{Atom, QualName}; use string_cache::{Atom, QualName};
use url::Url; use url::Url;
@ -283,7 +284,7 @@ pub trait DocumentHelpers<'a> {
/// https://w3c.github.io/animation-timing/#dfn-invoke-callbacks-algorithm /// https://w3c.github.io/animation-timing/#dfn-invoke-callbacks-algorithm
fn invoke_animation_callbacks(self); fn invoke_animation_callbacks(self);
fn prepare_async_load(self, load: LoadType) -> PendingAsyncLoad; fn prepare_async_load(self, load: LoadType) -> PendingAsyncLoad;
fn load_async(self, load: LoadType, listener: Box<AsyncResponseTarget + Send>); fn load_async(self, load: LoadType, listener: AsyncResponseTarget);
fn load_sync(self, load: LoadType) -> Result<(Metadata, Vec<u8>), String>; fn load_sync(self, load: LoadType) -> Result<(Metadata, Vec<u8>), String>;
fn finish_load(self, load: LoadType); fn finish_load(self, load: LoadType);
fn set_current_parser(self, script: Option<&ServoHTMLParser>); fn set_current_parser(self, script: Option<&ServoHTMLParser>);
@ -968,7 +969,7 @@ impl<'a> DocumentHelpers<'a> for &'a Document {
loader.prepare_async_load(load) loader.prepare_async_load(load)
} }
fn load_async(self, load: LoadType, listener: Box<AsyncResponseTarget + Send>) { fn load_async(self, load: LoadType, listener: AsyncResponseTarget) {
let mut loader = self.loader.borrow_mut(); let mut loader = self.loader.borrow_mut();
loader.load_async(load, listener) loader.load_async(load, listener)
} }
@ -1720,7 +1721,7 @@ impl<'a> DocumentMethods for &'a Document {
return Err(Security); return Err(Security);
} }
let window = self.window.root(); let window = self.window.root();
let (tx, rx) = channel(); let (tx, rx) = ipc::channel().unwrap();
let _ = window.r().resource_task().send(GetCookiesForUrl(url, tx, NonHTTP)); let _ = window.r().resource_task().send(GetCookiesForUrl(url, tx, NonHTTP));
let cookies = rx.recv().unwrap(); let cookies = rx.recv().unwrap();
Ok(cookies.unwrap_or("".to_owned())) Ok(cookies.unwrap_or("".to_owned()))

View file

@ -40,7 +40,9 @@ use js::jsval::UndefinedValue;
use encoding::all::UTF_8; use encoding::all::UTF_8;
use encoding::label::encoding_from_whatwg_label; use encoding::label::encoding_from_whatwg_label;
use encoding::types::{Encoding, EncodingRef, DecoderTrap}; use encoding::types::{Encoding, EncodingRef, DecoderTrap};
use net_traits::{Metadata, AsyncResponseListener}; use ipc_channel::ipc;
use ipc_channel::router::ROUTER;
use net_traits::{Metadata, AsyncResponseListener, AsyncResponseTarget};
use util::str::{DOMString, HTML_SPACE_CHARACTERS, StaticStringVec}; use util::str::{DOMString, HTML_SPACE_CHARACTERS, StaticStringVec};
use html5ever::tree_builder::NextParserState; use html5ever::tree_builder::NextParserState;
use std::cell::{RefCell, Cell}; use std::cell::{RefCell, Cell};
@ -330,12 +332,19 @@ impl<'a> HTMLScriptElementHelpers for &'a HTMLScriptElement {
url: url.clone(), url: url.clone(),
})); }));
let (action_sender, action_receiver) = ipc::channel().unwrap();
let listener = box NetworkListener { let listener = box NetworkListener {
context: context, context: context,
script_chan: script_chan, script_chan: script_chan,
}; };
let response_target = AsyncResponseTarget {
sender: action_sender,
};
ROUTER.add_route(action_receiver.to_opaque(), box move |message| {
listener.notify(message.to().unwrap());
});
doc.r().load_async(LoadType::Script(url), listener); doc.r().load_async(LoadType::Script(url), response_target);
if self.parser_inserted.get() { if self.parser_inserted.get() {
doc.r().get_current_parser().unwrap().r().suspend(); doc.r().get_current_parser().unwrap().r().suspend();

View file

@ -74,8 +74,9 @@ use std::default::Default;
use std::ffi::CString; use std::ffi::CString;
use std::mem as std_mem; use std::mem as std_mem;
use std::rc::Rc; use std::rc::Rc;
use std::sync::mpsc::{channel, Receiver}; use std::sync::Arc;
use std::sync::mpsc::TryRecvError::{Empty, Disconnected}; use std::sync::mpsc::TryRecvError::{Empty, Disconnected};
use std::sync::mpsc::{channel, Receiver};
use time; use time;
/// Current state of the window object /// Current state of the window object
@ -173,7 +174,7 @@ pub struct Window {
window_size: Cell<Option<WindowSizeData>>, window_size: Cell<Option<WindowSizeData>>,
/// Associated resource task for use by DOM objects like XMLHttpRequest /// Associated resource task for use by DOM objects like XMLHttpRequest
resource_task: ResourceTask, resource_task: Arc<ResourceTask>,
/// A handle for communicating messages to the storage task. /// A handle for communicating messages to the storage task.
storage_task: StorageTask, storage_task: StorageTask,
@ -883,7 +884,7 @@ impl<'a> WindowHelpers for &'a Window {
} }
fn resource_task(self) -> ResourceTask { fn resource_task(self) -> ResourceTask {
self.resource_task.clone() (*self.resource_task).clone()
} }
fn mem_profiler_chan(self) -> mem::ProfilerChan { fn mem_profiler_chan(self) -> mem::ProfilerChan {
@ -1035,7 +1036,7 @@ impl Window {
control_chan: ScriptControlChan, control_chan: ScriptControlChan,
compositor: ScriptListener, compositor: ScriptListener,
image_cache_task: ImageCacheTask, image_cache_task: ImageCacheTask,
resource_task: ResourceTask, resource_task: Arc<ResourceTask>,
storage_task: StorageTask, storage_task: StorageTask,
mem_profiler_chan: mem::ProfilerChan, mem_profiler_chan: mem::ProfilerChan,
devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>, devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,

View file

@ -46,12 +46,14 @@ use js::jsval::{JSVal, NullValue, UndefinedValue};
use net_traits::ControlMsg::Load; use net_traits::ControlMsg::Load;
use net_traits::{ResourceTask, ResourceCORSData, LoadData, LoadConsumer}; use net_traits::{ResourceTask, ResourceCORSData, LoadData, LoadConsumer};
use net_traits::{AsyncResponseListener, Metadata}; use net_traits::{AsyncResponseListener, AsyncResponseTarget, Metadata};
use cors::{allow_cross_origin_request, CORSRequest, RequestMode, AsyncCORSResponseListener}; use cors::{allow_cross_origin_request, CORSRequest, RequestMode, AsyncCORSResponseListener};
use cors::CORSResponse; use cors::CORSResponse;
use util::str::DOMString; use util::str::DOMString;
use util::task::spawn_named; use util::task::spawn_named;
use ipc_channel::ipc;
use ipc_channel::router::ROUTER;
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::borrow::ToOwned; use std::borrow::ToOwned;
use std::cell::{RefCell, Cell}; use std::cell::{RefCell, Cell};
@ -270,11 +272,18 @@ impl XMLHttpRequest {
} }
} }
let (action_sender, action_receiver) = ipc::channel().unwrap();
let listener = box NetworkListener { let listener = box NetworkListener {
context: context, context: context,
script_chan: script_chan, script_chan: script_chan,
}; };
resource_task.send(Load(load_data, LoadConsumer::Listener(listener))).unwrap(); let response_target = AsyncResponseTarget {
sender: action_sender,
};
ROUTER.add_route(action_receiver.to_opaque(), box move |message| {
listener.notify(message.to().unwrap());
});
resource_task.send(Load(load_data, LoadConsumer::Listener(response_target))).unwrap();
} }
} }
@ -558,8 +567,11 @@ impl<'a> XMLHttpRequestMethods for &'a XMLHttpRequest {
}; };
let mut combined_headers = load_data.headers.clone(); let mut combined_headers = load_data.headers.clone();
combined_headers.extend(load_data.preserved_headers.iter()); combined_headers.extend(load_data.preserved_headers.iter());
let cors_request = CORSRequest::maybe_new(referer_url.clone(), load_data.url.clone(), mode, let cors_request = CORSRequest::maybe_new(referer_url.clone(),
load_data.method.clone(), combined_headers); load_data.url.clone(),
mode,
load_data.method.clone(),
combined_headers);
match cors_request { match cors_request {
Ok(None) => { Ok(None) => {
let mut buf = String::new(); let mut buf = String::new();
@ -781,7 +793,8 @@ impl<'a> PrivateXMLHttpRequestHelpers for &'a XMLHttpRequest {
}; };
// XXXManishearth Clear cache entries in case of a network error // XXXManishearth Clear cache entries in case of a network error
self.process_partial_response(XHRProgress::HeadersReceived(gen_id, self.process_partial_response(XHRProgress::HeadersReceived(gen_id,
metadata.headers, metadata.status)); metadata.headers,
metadata.status));
Ok(()) Ok(())
} }

View file

@ -3,7 +3,7 @@
* 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 script_task::{ScriptChan, ScriptMsg, Runnable}; use script_task::{ScriptChan, ScriptMsg, Runnable};
use net_traits::{AsyncResponseTarget, AsyncResponseListener, ResponseAction}; use net_traits::{AsyncResponseListener, ResponseAction};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
/// An off-thread sink for async network event runnables. All such events are forwarded to /// An off-thread sink for async network event runnables. All such events are forwarded to
@ -13,12 +13,14 @@ pub struct NetworkListener<T: AsyncResponseListener + PreInvoke + Send + 'static
pub script_chan: Box<ScriptChan+Send>, pub script_chan: Box<ScriptChan+Send>,
} }
impl<T: AsyncResponseListener + PreInvoke + Send + 'static> AsyncResponseTarget for NetworkListener<T> { impl<T: AsyncResponseListener + PreInvoke + Send + 'static> NetworkListener<T> {
fn invoke_with_listener(&self, action: ResponseAction) { pub fn notify(&self, action: ResponseAction) {
self.script_chan.send(ScriptMsg::RunnableMsg(box ListenerRunnable { if let Err(err) = self.script_chan.send(ScriptMsg::RunnableMsg(box ListenerRunnable {
context: self.context.clone(), context: self.context.clone(),
action: action, action: action,
})).unwrap(); })) {
warn!("failed to deliver network data: {:?}", err);
}
} }
} }

View file

@ -67,8 +67,8 @@ use msg::constellation_msg::{LoadData, PipelineId, SubpageId, MozBrowserEvent, W
use msg::constellation_msg::{Failure, WindowSizeData, PipelineExitType}; use msg::constellation_msg::{Failure, WindowSizeData, PipelineExitType};
use msg::constellation_msg::Msg as ConstellationMsg; use msg::constellation_msg::Msg as ConstellationMsg;
use msg::webdriver_msg::WebDriverScriptCommand; use msg::webdriver_msg::WebDriverScriptCommand;
use net_traits::{ResourceTask, LoadConsumer, ControlMsg, Metadata};
use net_traits::LoadData as NetLoadData; use net_traits::LoadData as NetLoadData;
use net_traits::{AsyncResponseTarget, ResourceTask, LoadConsumer, ControlMsg, Metadata};
use net_traits::image_cache_task::{ImageCacheChan, ImageCacheTask, ImageCacheResult}; use net_traits::image_cache_task::{ImageCacheChan, ImageCacheTask, ImageCacheResult};
use net_traits::storage_task::StorageTask; use net_traits::storage_task::StorageTask;
use profile_traits::mem::{self, Report, Reporter, ReporterRequest, ReportKind, ReportsChan}; use profile_traits::mem::{self, Report, Reporter, ReporterRequest, ReportKind, ReportsChan};
@ -287,8 +287,9 @@ pub struct ScriptTask {
incomplete_loads: DOMRefCell<Vec<InProgressLoad>>, incomplete_loads: DOMRefCell<Vec<InProgressLoad>>,
/// A handle to the image cache task. /// A handle to the image cache task.
image_cache_task: ImageCacheTask, image_cache_task: ImageCacheTask,
/// A handle to the resource task. /// A handle to the resource task. This is an `Arc` to avoid running out of file descriptors if
resource_task: ResourceTask, /// there are many iframes.
resource_task: Arc<ResourceTask>,
/// A handle to the storage task. /// A handle to the storage task.
storage_task: StorageTask, storage_task: StorageTask,
@ -418,7 +419,7 @@ impl ScriptTaskFactory for ScriptTask {
control_chan, control_chan,
control_port, control_port,
constellation_chan, constellation_chan,
resource_task, Arc::new(resource_task),
storage_task, storage_task,
image_cache_task, image_cache_task,
mem_profiler_chan.clone(), mem_profiler_chan.clone(),
@ -504,7 +505,7 @@ impl ScriptTask {
control_chan: ScriptControlChan, control_chan: ScriptControlChan,
control_port: Receiver<ConstellationControlMsg>, control_port: Receiver<ConstellationControlMsg>,
constellation_chan: ConstellationChan, constellation_chan: ConstellationChan,
resource_task: ResourceTask, resource_task: Arc<ResourceTask>,
storage_task: StorageTask, storage_task: StorageTask,
image_cache_task: ImageCacheTask, image_cache_task: ImageCacheTask,
mem_profiler_chan: mem::ProfilerChan, mem_profiler_chan: mem::ProfilerChan,
@ -1415,7 +1416,9 @@ impl ScriptTask {
}); });
let content_type = match metadata.content_type { let content_type = match metadata.content_type {
Some(ContentType(Mime(TopLevel::Text, SubLevel::Plain, _))) => Some("text/plain".to_owned()), Some(ContentType(Mime(TopLevel::Text, SubLevel::Plain, _))) => {
Some("text/plain".to_owned())
}
_ => None _ => None
}; };
@ -1680,10 +1683,17 @@ impl ScriptTask {
let context = Arc::new(Mutex::new(ParserContext::new(id, subpage, script_chan.clone(), let context = Arc::new(Mutex::new(ParserContext::new(id, subpage, script_chan.clone(),
load_data.url.clone()))); load_data.url.clone())));
let (action_sender, action_receiver) = ipc::channel().unwrap();
let listener = box NetworkListener { let listener = box NetworkListener {
context: context, context: context,
script_chan: script_chan.clone(), script_chan: script_chan.clone(),
}; };
ROUTER.add_route(action_receiver.to_opaque(), box move |message| {
listener.notify(message.to().unwrap());
});
let response_target = AsyncResponseTarget {
sender: action_sender,
};
if load_data.url.scheme == "javascript" { if load_data.url.scheme == "javascript" {
load_data.url = Url::parse("about:blank").unwrap(); load_data.url = Url::parse("about:blank").unwrap();
@ -1697,7 +1707,7 @@ impl ScriptTask {
data: load_data.data, data: load_data.data,
cors: None, cors: None,
pipeline_id: Some(id), pipeline_id: Some(id),
}, LoadConsumer::Listener(listener))).unwrap(); }, LoadConsumer::Listener(response_target))).unwrap();
self.incomplete_loads.borrow_mut().push(incomplete); self.incomplete_loads.borrow_mut().push(incomplete);
} }

View file

@ -25,8 +25,11 @@ path = "../devtools_traits"
[dependencies.ipc-channel] [dependencies.ipc-channel]
git = "https://github.com/pcwalton/ipc-channel" git = "https://github.com/pcwalton/ipc-channel"
[dependencies.url]
version = "0.2"
features = [ "serde_serialization" ]
[dependencies] [dependencies]
url = "0.2.36"
libc = "0.1" libc = "0.1"
euclid = "0.1" euclid = "0.1"
serde = "0.4" serde = "0.4"

View file

@ -910,6 +910,7 @@ version = "0.0.1"
dependencies = [ dependencies = [
"cookie 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "cookie 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
"ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)",
"net 0.0.1", "net 0.0.1",
"net_traits 0.0.1", "net_traits 0.0.1",
"time 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",

View file

@ -100,9 +100,12 @@ optional = true
path = "../../support/android-rs-glue/glue" path = "../../support/android-rs-glue/glue"
optional = true optional = true
[dependencies.url]
version = "0.2"
features = [ "serde_serialization" ]
[dependencies] [dependencies]
env_logger = "0.3" env_logger = "0.3"
url = "0.2.36"
time = "0.1.12" time = "0.1.12"
bitflags = "0.3" bitflags = "0.3"
libc = "0.1" libc = "0.1"

View file

@ -23,13 +23,16 @@ features = ["unstable"]
version = "0.3" version = "0.3"
features = [ "serde-serialization" ] features = [ "serde-serialization" ]
[dependencies.url]
version = "0.2"
features = [ "serde_serialization" ]
[dependencies] [dependencies]
log = "0.3" log = "0.3"
encoding = "0.2" encoding = "0.2"
fnv = "1.0" fnv = "1.0"
rustc-serialize = "0.3" rustc-serialize = "0.3"
matches = "0.1" matches = "0.1"
url = "0.2.36"
bitflags = "0.3" bitflags = "0.3"
num = "0.1.24" num = "0.1.24"
lazy_static = "0.1.10" lazy_static = "0.1.10"

View file

@ -28,6 +28,10 @@ features = [ "serde-serialization" ]
[dependencies.ipc-channel] [dependencies.ipc-channel]
git = "https://github.com/pcwalton/ipc-channel" git = "https://github.com/pcwalton/ipc-channel"
[dependencies.url]
version = "0.2"
features = [ "serde_serialization" ]
[dependencies] [dependencies]
log = "0.3" log = "0.3"
bitflags = "0.3" bitflags = "0.3"
@ -37,7 +41,6 @@ rustc-serialize = "0.3"
smallvec = "0.1" smallvec = "0.1"
num_cpus = "0.2.2" num_cpus = "0.2.2"
num = "0.1.24" num = "0.1.24"
url = "0.2.36"
euclid = "0.1" euclid = "0.1"
serde = "0.4" serde = "0.4"
serde_macros = "0.4" serde_macros = "0.4"

View file

@ -23,8 +23,11 @@ features = [ "serde-serialization" ]
[dependencies.ipc-channel] [dependencies.ipc-channel]
git = "https://github.com/pcwalton/ipc-channel" git = "https://github.com/pcwalton/ipc-channel"
[dependencies.url]
version = "0.2"
features = [ "serde_serialization" ]
[dependencies] [dependencies]
log = "0.3" log = "0.3"
rustc-serialize = "0.3.4" rustc-serialize = "0.3.4"
url = "0.2.36"
uuid = "0.1" uuid = "0.1"

View file

@ -17,6 +17,9 @@ path = "../../../components/net_traits"
[dependencies.util] [dependencies.util]
path = "../../../components/util" path = "../../../components/util"
[dependencies.ipc-channel]
git = "https://github.com/pcwalton/ipc-channel"
[dependencies] [dependencies]
cookie = "0.1" cookie = "0.1"
hyper = "0.6" hyper = "0.6"

View file

@ -4,6 +4,7 @@
extern crate hyper; extern crate hyper;
use ipc_channel::ipc;
use net_traits::LoadConsumer::Channel; use net_traits::LoadConsumer::Channel;
use net_traits::LoadData; use net_traits::LoadData;
use net_traits::ProgressMsg::{Payload, Done}; use net_traits::ProgressMsg::{Payload, Done};
@ -19,7 +20,7 @@ fn assert_parse(url: &'static str,
use url::Url; use url::Url;
use net::data_loader::load; use net::data_loader::load;
let (start_chan, start_port) = channel(); let (start_chan, start_port) = ipc::channel().unwrap();
load(LoadData::new(Url::parse(url).unwrap(), None), Channel(start_chan)); load(LoadData::new(Url::parse(url).unwrap(), None), Channel(start_chan));
let response = start_port.recv().unwrap(); let response = start_port.recv().unwrap();

View file

@ -7,6 +7,7 @@ use net::hsts::HSTSEntry;
use net_traits::IncludeSubdomains; use net_traits::IncludeSubdomains;
use net::hsts::{secure_url, preload_hsts_domains}; use net::hsts::{secure_url, preload_hsts_domains};
use net::resource_task::ResourceManager; use net::resource_task::ResourceManager;
use ipc_channel::ipc;
use std::sync::mpsc::channel; use std::sync::mpsc::channel;
use url::Url; use url::Url;
use time; use time;
@ -17,7 +18,7 @@ fn test_add_hsts_entry_to_resource_manager_adds_an_hsts_entry() {
entries: Vec::new() entries: Vec::new()
}; };
let (tx, _) = channel(); let (tx, _) = ipc::channel().unwrap();
let mut manager = ResourceManager::new(None, tx, list, None); let mut manager = ResourceManager::new(None, tx, list, None);
let entry = HSTSEntry::new( let entry = HSTSEntry::new(

View file

@ -4,6 +4,7 @@
#![cfg_attr(test, feature(box_raw))] #![cfg_attr(test, feature(box_raw))]
extern crate ipc_channel;
extern crate net; extern crate net;
extern crate net_traits; extern crate net_traits;
extern crate url; extern crate url;

View file

@ -2,9 +2,8 @@
* 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 net::resource_task::new_resource_task; use ipc_channel::ipc;
use net::resource_task::parse_hostsfile; use net::resource_task::{new_resource_task, parse_hostsfile, replace_hosts};
use net::resource_task::replace_hosts;
use net_traits::{ControlMsg, LoadData, LoadConsumer}; use net_traits::{ControlMsg, LoadData, LoadConsumer};
use net_traits::ProgressMsg; use net_traits::ProgressMsg;
use std::borrow::ToOwned; use std::borrow::ToOwned;
@ -21,7 +20,7 @@ fn test_exit() {
#[test] #[test]
fn test_bad_scheme() { fn test_bad_scheme() {
let resource_task = new_resource_task(None, None); let resource_task = new_resource_task(None, None);
let (start_chan, start) = channel(); let (start_chan, start) = ipc::channel().unwrap();
let url = Url::parse("bogus://whatever").unwrap(); let url = Url::parse("bogus://whatever").unwrap();
resource_task.send(ControlMsg::Load(LoadData::new(url, None), LoadConsumer::Channel(start_chan))).unwrap(); resource_task.send(ControlMsg::Load(LoadData::new(url, None), LoadConsumer::Channel(start_chan))).unwrap();
let response = start.recv().unwrap(); let response = start.recv().unwrap();
@ -170,7 +169,7 @@ fn test_replace_hosts() {
//Start the resource task and make a request to our TCP server //Start the resource task and make a request to our TCP server
let resource_task = new_resource_task(None, None); let resource_task = new_resource_task(None, None);
let (start_chan, _) = channel(); let (start_chan, _start_port) = ipc::channel().unwrap();
let url = Url::parse(&format!("http://foo.bar.com:{}", port)).unwrap(); let url = Url::parse(&format!("http://foo.bar.com:{}", port)).unwrap();
let msg = ControlMsg::Load(replace_hosts(LoadData::new(url, None), host_table), let msg = ControlMsg::Load(replace_hosts(LoadData::new(url, None), host_table),
LoadConsumer::Channel(start_chan)); LoadConsumer::Channel(start_chan));