aboutsummaryrefslogtreecommitdiffstats
path: root/components/net_traits/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/net_traits/lib.rs')
-rw-r--r--components/net_traits/lib.rs218
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
+ }
+ }
+ }
+}
+
+