diff options
Diffstat (limited to 'components/net_traits/lib.rs')
-rw-r--r-- | components/net_traits/lib.rs | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/components/net_traits/lib.rs b/components/net_traits/lib.rs new file mode 100644 index 00000000000..abf084f2270 --- /dev/null +++ b/components/net_traits/lib.rs @@ -0,0 +1,218 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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/. */ + +#![feature(box_syntax)] +#![feature(collections)] +#![feature(core)] +#![feature(int_uint)] +#![feature(rustc_private)] +#![feature(std_misc)] + +extern crate geom; +extern crate hyper; +#[macro_use] +extern crate log; +extern crate png; +extern crate profile; +extern crate stb_image; +extern crate url; +extern crate util; + +use hyper::header::Headers; +use hyper::http::RawStatus; +use hyper::method::Method; +use hyper::mime::{Mime, Attr}; +use url::Url; + +use std::borrow::IntoCow; +use std::sync::mpsc::{channel, Receiver, Sender}; + +pub mod image_cache_task; +pub mod local_image_cache; +pub mod storage_task; + +/// Image handling. +/// +/// It may be surprising that this goes in the network crate as opposed to the graphics crate. +/// However, image handling is generally very integrated with the network stack (especially where +/// caching is involved) and as a result it must live in here. +pub mod image { + pub mod base; + pub mod holder; +} + +#[derive(Clone)] +pub struct LoadData { + pub url: Url, + pub method: Method, + /// Headers that will apply to the initial request only + pub headers: Headers, + /// Headers that will apply to the initial request and any redirects + pub preserved_headers: Headers, + pub data: Option<Vec<u8>>, + pub cors: Option<ResourceCORSData>, + pub consumer: Sender<LoadResponse>, +} + +impl LoadData { + pub fn new(url: Url, consumer: Sender<LoadResponse>) -> LoadData { + LoadData { + url: url, + method: Method::Get, + headers: Headers::new(), + preserved_headers: Headers::new(), + data: None, + cors: None, + consumer: consumer, + } + } +} + +/// Handle to a resource task +pub type ResourceTask = Sender<ControlMsg>; + +pub enum ControlMsg { + /// Request the data associated with a particular URL + Load(LoadData), + /// Store a set of cookies for a given originating URL + SetCookiesForUrl(Url, String, CookieSource), + /// Retrieve the stored cookies for a given URL + GetCookiesForUrl(Url, Sender<Option<String>>, CookieSource), + Exit +} + +/// Message sent in response to `Load`. Contains metadata, and a port +/// for receiving the data. +/// +/// Even if loading fails immediately, we send one of these and the +/// progress_port will provide the error. +pub struct LoadResponse { + /// Metadata, such as from HTTP headers. + pub metadata: Metadata, + /// Port for reading data. + pub progress_port: Receiver<ProgressMsg>, +} + +#[derive(Clone)] +pub struct ResourceCORSData { + /// CORS Preflight flag + pub preflight: bool, + /// Origin of CORS Request + pub origin: Url +} + +/// Metadata about a loaded resource, such as is obtained from HTTP headers. +#[derive(Clone)] +pub struct Metadata { + /// Final URL after redirects. + pub final_url: Url, + + /// MIME type / subtype. + pub content_type: Option<(String, String)>, + + /// Character set. + pub charset: Option<String>, + + /// Headers + pub headers: Option<Headers>, + + /// HTTP Status + pub status: Option<RawStatus>, +} + +impl Metadata { + /// Metadata with defaults for everything optional. + pub fn default(url: Url) -> Self { + Metadata { + final_url: url, + content_type: None, + charset: None, + headers: None, + // http://fetch.spec.whatwg.org/#concept-response-status-message + status: Some(RawStatus(200, "OK".into_cow())), + } + } + + /// Extract the parts of a Mime that we care about. + pub fn set_content_type(&mut self, content_type: Option<&Mime>) { + match content_type { + None => (), + Some(&Mime(ref type_, ref subtype, ref parameters)) => { + self.content_type = Some((type_.to_string(), subtype.to_string())); + for &(ref k, ref v) in parameters.iter() { + if &Attr::Charset == k { + self.charset = Some(v.to_string()); + } + } + } + } + } +} + +/// The creator of a given cookie +#[derive(PartialEq, Copy)] +pub enum CookieSource { + /// An HTTP API + HTTP, + /// A non-HTTP API + NonHTTP, +} + +/// Messages sent in response to a `Load` message +#[derive(PartialEq,Debug)] +pub enum ProgressMsg { + /// Binary data - there may be multiple of these + Payload(Vec<u8>), + /// Indicates loading is complete, either successfully or not + Done(Result<(), String>) +} + +/// Convenience function for synchronously loading a whole resource. +pub fn load_whole_resource(resource_task: &ResourceTask, url: Url) + -> Result<(Metadata, Vec<u8>), String> { + let (start_chan, start_port) = channel(); + resource_task.send(ControlMsg::Load(LoadData::new(url, start_chan))).unwrap(); + let response = start_port.recv().unwrap(); + + let mut buf = vec!(); + loop { + match response.progress_port.recv().unwrap() { + ProgressMsg::Payload(data) => buf.push_all(&data), + ProgressMsg::Done(Ok(())) => return Ok((response.metadata, buf)), + ProgressMsg::Done(Err(e)) => return Err(e) + } + } +} + +/// Load a URL asynchronously and iterate over chunks of bytes from the response. +pub fn load_bytes_iter(resource_task: &ResourceTask, url: Url) -> (Metadata, ProgressMsgPortIterator) { + let (input_chan, input_port) = channel(); + resource_task.send(ControlMsg::Load(LoadData::new(url, input_chan))).unwrap(); + + let response = input_port.recv().unwrap(); + let iter = ProgressMsgPortIterator { progress_port: response.progress_port }; + (response.metadata, iter) +} + +/// Iterator that reads chunks of bytes from a ProgressMsg port +pub struct ProgressMsgPortIterator { + progress_port: Receiver<ProgressMsg> +} + +impl Iterator for ProgressMsgPortIterator { + type Item = Vec<u8>; + + fn next(&mut self) -> Option<Vec<u8>> { + match self.progress_port.recv().unwrap() { + ProgressMsg::Payload(data) => Some(data), + ProgressMsg::Done(Ok(())) => None, + ProgressMsg::Done(Err(e)) => { + error!("error receiving bytes: {}", e); + None + } + } + } +} + + |