aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/net
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/net')
-rw-r--r--src/components/net/data_loader.rs154
-rw-r--r--src/components/net/fetch/cors_cache.rs316
-rw-r--r--src/components/net/fetch/request.rs149
-rw-r--r--src/components/net/fetch/response.rs144
-rw-r--r--src/components/net/file_loader.rs50
-rw-r--r--src/components/net/http_loader.rs167
-rw-r--r--src/components/net/image/base.rs67
-rw-r--r--src/components/net/image/holder.rs109
-rw-r--r--src/components/net/image/test.jpegbin4962 -> 0 bytes
-rw-r--r--src/components/net/image_cache_task.rs993
-rw-r--r--src/components/net/local_image_cache.rs166
-rw-r--r--src/components/net/net.rs47
-rw-r--r--src/components/net/resource_task.rs267
13 files changed, 0 insertions, 2629 deletions
diff --git a/src/components/net/data_loader.rs b/src/components/net/data_loader.rs
deleted file mode 100644
index 5d9fb776674..00000000000
--- a/src/components/net/data_loader.rs
+++ /dev/null
@@ -1,154 +0,0 @@
-/* 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/. */
-
-use std::str;
-
-use resource_task::{Done, Payload, Metadata, LoadData, LoadResponse, LoaderTask, start_sending};
-
-use serialize::base64::FromBase64;
-
-use http::headers::test_utils::from_stream_with_str;
-use http::headers::content_type::MediaType;
-use url::{percent_decode, NonRelativeSchemeData};
-
-
-pub fn factory() -> LoaderTask {
- proc(url, start_chan) {
- // 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.
- load(url, start_chan)
- }
-}
-
-fn load(load_data: LoadData, start_chan: Sender<LoadResponse>) {
- let url = load_data.url;
- assert!("data" == url.scheme.as_slice());
-
- let mut metadata = Metadata::default(url.clone());
-
- // Split out content type and data.
- let mut scheme_data = match url.scheme_data {
- NonRelativeSchemeData(scheme_data) => scheme_data,
- _ => fail!("Expected a non-relative scheme URL.")
- };
- match url.query {
- Some(query) => {
- scheme_data.push_str("?");
- scheme_data.push_str(query.as_slice());
- },
- None => ()
- }
- let parts: Vec<&str> = scheme_data.as_slice().splitn(',', 1).collect();
- if parts.len() != 2 {
- start_sending(start_chan, metadata).send(Done(Err("invalid data uri".to_string())));
- 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;
- let mut ct_str = parts[0];
- if ct_str.ends_with(";base64") {
- is_base64 = true;
- ct_str = ct_str.slice_to(ct_str.as_bytes().len() - 7);
- }
-
- // Parse the content type using rust-http.
- // FIXME: this can go into an infinite loop! (rust-http #25)
- let content_type: Option<MediaType> = from_stream_with_str(ct_str);
- metadata.set_content_type(&content_type);
-
- let progress_chan = start_sending(start_chan, metadata);
- let bytes = percent_decode(parts[1].as_bytes());
-
- if is_base64 {
- // FIXME(#2909): It’s unclear what to do with non-alphabet characters,
- // but Acid 3 apparently depends on spaces being ignored.
- let bytes = bytes.move_iter().filter(|&b| b != ' ' as u8).collect::<Vec<u8>>();
- // FIXME(#2877): use bytes.as_slice().from_base64() when we upgrade to a Rust version
- // that includes https://github.com/rust-lang/rust/pull/15810
- let fake_utf8 = unsafe { str::raw::from_utf8(bytes.as_slice()) };
- match fake_utf8.from_base64() {
- Err(..) => {
- progress_chan.send(Done(Err("non-base64 data uri".to_string())));
- }
- Ok(data) => {
- progress_chan.send(Payload(data));
- progress_chan.send(Done(Ok(())));
- }
- }
- } else {
- progress_chan.send(Payload(bytes));
- progress_chan.send(Done(Ok(())));
- }
-}
-
-#[cfg(test)]
-fn assert_parse(url: &'static str,
- content_type: Option<(String, String)>,
- charset: Option<String>,
- data: Option<Vec<u8>>) {
- use std::comm;
- use url::Url;
-
- let (start_chan, start_port) = comm::channel();
- load(LoadData::new(Url::parse(url).unwrap()), start_chan);
-
- let response = start_port.recv();
- assert_eq!(&response.metadata.content_type, &content_type);
- assert_eq!(&response.metadata.charset, &charset);
-
- let progress = response.progress_port.recv();
-
- match data {
- None => {
- assert_eq!(progress, Done(Err("invalid data uri".to_string())));
- }
- Some(dat) => {
- assert_eq!(progress, Payload(dat));
- assert_eq!(response.progress_port.recv(), Done(Ok(())));
- }
- }
-}
-
-#[test]
-fn empty_invalid() {
- assert_parse("data:", None, None, None);
-}
-
-#[test]
-fn plain() {
- assert_parse("data:,hello%20world", None, None, Some(b"hello world".iter().map(|&x| x).collect()));
-}
-
-#[test]
-fn plain_ct() {
- assert_parse("data:text/plain,hello",
- Some(("text".to_string(), "plain".to_string())), None, Some(b"hello".iter().map(|&x| x).collect()));
-}
-
-#[test]
-fn plain_charset() {
- assert_parse("data:text/plain;charset=latin1,hello",
- Some(("text".to_string(), "plain".to_string())), Some("latin1".to_string()), Some(b"hello".iter().map(|&x| x).collect()));
-}
-
-#[test]
-fn base64() {
- assert_parse("data:;base64,C62+7w==", None, None, Some(vec!(0x0B, 0xAD, 0xBE, 0xEF)));
-}
-
-#[test]
-fn base64_ct() {
- assert_parse("data:application/octet-stream;base64,C62+7w==",
- Some(("application".to_string(), "octet-stream".to_string())), None, Some(vec!(0x0B, 0xAD, 0xBE, 0xEF)));
-}
-
-#[test]
-fn base64_charset() {
- assert_parse("data:text/plain;charset=koi8-r;base64,8PLl9+XkIO3l5Pfl5A==",
- Some(("text".to_string(), "plain".to_string())), Some("koi8-r".to_string()),
- Some(vec!(0xF0, 0xF2, 0xE5, 0xF7, 0xE5, 0xE4, 0x20, 0xED, 0xE5, 0xE4, 0xF7, 0xE5, 0xE4)));
-}
diff --git a/src/components/net/fetch/cors_cache.rs b/src/components/net/fetch/cors_cache.rs
deleted file mode 100644
index fb6676e8064..00000000000
--- a/src/components/net/fetch/cors_cache.rs
+++ /dev/null
@@ -1,316 +0,0 @@
-/* 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/. */
-
-//! An implementation of the [CORS preflight cache](http://fetch.spec.whatwg.org/#cors-preflight-cache)
-//! For now this library is XHR-specific.
-//! For stuff involving `<img>`, `<iframe>`, `<form>`, etc please check what
-//! the request mode should be and compare with the fetch spec
-//! This library will eventually become the core of the Fetch crate
-//! with CORSRequest being expanded into FetchRequest (etc)
-
-use http::method::Method;
-use std::ascii::StrAsciiExt;
-use std::comm::{Sender, Receiver, channel};
-use time;
-use time::{now, Timespec};
-use url::Url;
-
-/// Union type for CORS cache entries
-///
-/// Each entry might pertain to a header or method
-#[deriving(Clone)]
-pub enum HeaderOrMethod {
- HeaderData(String),
- MethodData(Method)
-}
-
-impl HeaderOrMethod {
- fn match_header(&self, header_name: &str) -> bool {
- match *self {
- HeaderData(ref s) => s.as_slice().eq_ignore_ascii_case(header_name),
- _ => false
- }
- }
-
- fn match_method(&self, method: &Method) -> bool {
- match *self {
- MethodData(ref m) => m == method,
- _ => false
- }
- }
-}
-
-/// An entry in the CORS cache
-#[deriving(Clone)]
-pub struct CORSCacheEntry {
- pub origin: Url,
- pub url: Url,
- pub max_age: uint,
- pub credentials: bool,
- pub header_or_method: HeaderOrMethod,
- created: Timespec
-}
-
-impl CORSCacheEntry {
- fn new (origin:Url, url: Url, max_age: uint, credentials: bool, header_or_method: HeaderOrMethod) -> CORSCacheEntry {
- CORSCacheEntry {
- origin: origin,
- url: url,
- max_age: max_age,
- credentials: credentials,
- header_or_method: header_or_method,
- created: time::now().to_timespec()
- }
- }
-}
-
-/// Properties of Request required to cache match.
-pub struct CacheRequestDetails {
- pub origin: Url,
- pub destination: Url,
- pub credentials: bool
-}
-
-/// Trait for a generic CORS Cache
-pub trait CORSCache {
- /// [Clear the cache](http://fetch.spec.whatwg.org/#concept-cache-clear)
- fn clear (&mut self, request: CacheRequestDetails);
-
- /// Remove old entries
- fn cleanup(&mut self);
-
- /// Returns true if an entry with a [matching header](http://fetch.spec.whatwg.org/#concept-cache-match-header) is found
- fn match_header(&mut self, request: CacheRequestDetails, header_name: &str) -> bool;
-
- /// Updates max age if an entry for a [matching header](http://fetch.spec.whatwg.org/#concept-cache-match-header) is found.
- ///
- /// If not, it will insert an equivalent entry
- fn match_header_and_update(&mut self, request: CacheRequestDetails, header_name: &str, new_max_age: uint) -> bool;
-
- /// Returns true if an entry with a [matching method](http://fetch.spec.whatwg.org/#concept-cache-match-method) is found
- fn match_method(&mut self, request: CacheRequestDetails, method: Method) -> bool;
-
- /// Updates max age if an entry for [a matching method](http://fetch.spec.whatwg.org/#concept-cache-match-method) is found.
- ///
- /// If not, it will insert an equivalent entry
- fn match_method_and_update(&mut self, request: CacheRequestDetails, method: Method, new_max_age: uint) -> bool;
- /// Insert an entry
- fn insert(&mut self, entry: CORSCacheEntry);
-}
-
-/// A simple, vector-based CORS Cache
-#[deriving(Clone)]
-#[unstable = "This might later be replaced with a HashMap-like entity, though that requires a separate Origin struct"]
-pub struct BasicCORSCache(Vec<CORSCacheEntry>);
-
-impl BasicCORSCache {
- fn find_entry_by_header<'a>(&'a mut self, request: &CacheRequestDetails, header_name: &str) -> Option<&'a mut CORSCacheEntry> {
- self.cleanup();
- let BasicCORSCache(ref mut buf) = *self;
- let entry = buf.mut_iter().find(|e| e.origin.scheme == request.origin.scheme &&
- e.origin.host() == request.origin.host() &&
- e.origin.port() == request.origin.port() &&
- e.url == request.destination &&
- e.credentials == request.credentials &&
- e.header_or_method.match_header(header_name));
- entry
- }
-
- fn find_entry_by_method<'a>(&'a mut self, request: &CacheRequestDetails, method: Method) -> Option<&'a mut CORSCacheEntry> {
- // we can take the method from CORSRequest itself
- self.cleanup();
- let BasicCORSCache(ref mut buf) = *self;
- let entry = buf.mut_iter().find(|e| e.origin.scheme == request.origin.scheme &&
- e.origin.host() == request.origin.host() &&
- e.origin.port() == request.origin.port() &&
- e.url == request.destination &&
- e.credentials == request.credentials &&
- e.header_or_method.match_method(&method));
- entry
- }
-}
-
-impl CORSCache for BasicCORSCache {
- /// http://fetch.spec.whatwg.org/#concept-cache-clear
- #[allow(dead_code)]
- fn clear (&mut self, request: CacheRequestDetails) {
- let BasicCORSCache(buf) = self.clone();
- let new_buf: Vec<CORSCacheEntry> = buf.move_iter().filter(|e| e.origin == request.origin && request.destination == e.url).collect();
- *self = BasicCORSCache(new_buf);
- }
-
- // Remove old entries
- fn cleanup(&mut self) {
- let BasicCORSCache(buf) = self.clone();
- let now = time::now().to_timespec();
- let new_buf: Vec<CORSCacheEntry> = buf.move_iter().filter(|e| now.sec > e.created.sec + e.max_age as i64).collect();
- *self = BasicCORSCache(new_buf);
- }
-
- fn match_header(&mut self, request: CacheRequestDetails, header_name: &str) -> bool {
- self.find_entry_by_header(&request, header_name).is_some()
- }
-
- fn match_header_and_update(&mut self, request: CacheRequestDetails, header_name: &str, new_max_age: uint) -> bool {
- match self.find_entry_by_header(&request, header_name).map(|e| e.max_age = new_max_age) {
- Some(_) => true,
- None => {
- self.insert(CORSCacheEntry::new(request.origin, request.destination, new_max_age,
- request.credentials, HeaderData(header_name.to_string())));
- false
- }
- }
- }
-
- fn match_method(&mut self, request: CacheRequestDetails, method: Method) -> bool {
- self.find_entry_by_method(&request, method).is_some()
- }
-
- fn match_method_and_update(&mut self, request: CacheRequestDetails, method: Method, new_max_age: uint) -> bool {
- match self.find_entry_by_method(&request, method.clone()).map(|e| e.max_age = new_max_age) {
- Some(_) => true,
- None => {
- self.insert(CORSCacheEntry::new(request.origin, request.destination, new_max_age,
- request.credentials, MethodData(method)));
- false
- }
- }
- }
-
- fn insert(&mut self, entry: CORSCacheEntry) {
- self.cleanup();
- let BasicCORSCache(ref mut buf) = *self;
- buf.push(entry);
- }
-}
-
-/// Various messages that can be sent to a CORSCacheTask
-pub enum CORSCacheTaskMsg {
- Clear(CacheRequestDetails, Sender<()>),
- Cleanup(Sender<()>),
- MatchHeader(CacheRequestDetails, String, Sender<bool>),
- MatchHeaderUpdate(CacheRequestDetails, String, uint, Sender<bool>),
- MatchMethod(CacheRequestDetails, Method, Sender<bool>),
- MatchMethodUpdate(CacheRequestDetails, Method, uint, Sender<bool>),
- Insert(CORSCacheEntry, Sender<()>),
- ExitMsg
-}
-
-/// A Sender to a CORSCacheTask
-///
-/// This can be used as a CORS Cache.
-/// The methods on this type block until they can run, and it behaves similar to a mutex
-pub type CORSCacheSender = Sender<CORSCacheTaskMsg>;
-
-impl CORSCache for CORSCacheSender {
- fn clear (&mut self, request: CacheRequestDetails) {
- let (tx, rx) = channel();
- self.send(Clear(request, tx));
- let _ = rx.recv_opt();
- }
-
- fn cleanup(&mut self) {
- let (tx, rx) = channel();
- self.send(Cleanup(tx));
- let _ = rx.recv_opt();
- }
-
- fn match_header(&mut self, request: CacheRequestDetails, header_name: &str) -> bool {
- let (tx, rx) = channel();
- self.send(MatchHeader(request, header_name.to_string(), tx));
- rx.recv_opt().unwrap_or(false)
- }
-
- fn match_header_and_update(&mut self, request: CacheRequestDetails, header_name: &str, new_max_age: uint) -> bool {
- let (tx, rx) = channel();
- self.send(MatchHeaderUpdate(request, header_name.to_string(), new_max_age, tx));
- rx.recv_opt().unwrap_or(false)
- }
-
- fn match_method(&mut self, request: CacheRequestDetails, method: Method) -> bool {
- let (tx, rx) = channel();
- self.send(MatchMethod(request, method, tx));
- rx.recv_opt().unwrap_or(false)
- }
-
- fn match_method_and_update(&mut self, request: CacheRequestDetails, method: Method, new_max_age: uint) -> bool {
- let (tx, rx) = channel();
- self.send(MatchMethodUpdate(request, method, new_max_age, tx));
- rx.recv_opt().unwrap_or(false)
- }
-
- fn insert(&mut self, entry: CORSCacheEntry) {
- let (tx, rx) = channel();
- self.send(Insert(entry, tx));
- let _ = rx.recv_opt();
- }
-}
-
-/// A simple task-based CORS Cache that can be sent messages
-///
-/// #Example
-/// ```
-/// let task = CORSCacheTask::new();
-/// let builder = TaskBuilder::new().named("XHRTask");
-/// let mut sender = task.get_sender();
-/// builder.spawn(proc() { task.run() });
-/// sender.insert(CORSCacheEntry::new(/* parameters here */));
-/// ```
-pub struct CORSCacheTask {
- receiver: Receiver<CORSCacheTaskMsg>,
- cache: BasicCORSCache,
- sender: CORSCacheSender
-}
-
-impl CORSCacheTask {
- pub fn new() -> CORSCacheTask {
- let (tx, rx) = channel();
- CORSCacheTask {
- receiver: rx,
- cache: BasicCORSCache(vec![]),
- sender: tx
- }
- }
-
- /// Provides a sender to the cache task
- pub fn get_sender(&self) -> CORSCacheSender {
- self.sender.clone()
- }
-
- /// Runs the cache task
- /// This blocks the current task, so it is advised
- /// to spawn a new task for this
- /// Send ExitMsg to the associated Sender to exit
- pub fn run(&mut self) {
- loop {
- match self.receiver.recv() {
- Clear(request, tx) => {
- self.cache.clear(request);
- tx.send(());
- },
- Cleanup(tx) => {
- self.cache.cleanup();
- tx.send(());
- },
- MatchHeader(request, header, tx) => {
- tx.send(self.cache.match_header(request, header.as_slice()));
- },
- MatchHeaderUpdate(request, header, new_max_age, tx) => {
- tx.send(self.cache.match_header_and_update(request, header.as_slice(), new_max_age));
- },
- MatchMethod(request, method, tx) => {
- tx.send(self.cache.match_method(request, method));
- },
- MatchMethodUpdate(request, method, new_max_age, tx) => {
- tx.send(self.cache.match_method_and_update(request, method, new_max_age));
- },
- Insert(entry, tx) => {
- self.cache.insert(entry);
- tx.send(());
- },
- ExitMsg => break
- }
- }
- }
-}
diff --git a/src/components/net/fetch/request.rs b/src/components/net/fetch/request.rs
deleted file mode 100644
index c14efe9c59e..00000000000
--- a/src/components/net/fetch/request.rs
+++ /dev/null
@@ -1,149 +0,0 @@
-/* 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/. */
-
-use url::Url;
-use http::method::{Get, Method};
-use http::headers::request::HeaderCollection;
-use fetch::cors_cache::CORSCache;
-use fetch::response::Response;
-
-/// A [request context](http://fetch.spec.whatwg.org/#concept-request-context)
-pub enum Context {
- Audio, Beacon, CSPreport, Download, Embed, Eventsource,
- Favicon, Fetch, Font, Form, Frame, Hyperlink, IFrame, Image,
- ImageSet, Import, Internal, Location, Manifest, Object, Ping,
- Plugin, Prefetch, Script, ServiceWorker, SharedWorker, Subresource,
- Style, Track, Video, Worker, XMLHttpRequest, XSLT
-}
-
-/// A [request context frame type](http://fetch.spec.whatwg.org/#concept-request-context-frame-type)
-pub enum ContextFrameType {
- Auxiliary,
- TopLevel,
- Nested,
- ContextNone
-}
-
-/// A [referer](http://fetch.spec.whatwg.org/#concept-request-referrer)
-pub enum Referer {
- RefererNone,
- Client,
- RefererUrl(Url)
-}
-
-/// A [request mode](http://fetch.spec.whatwg.org/#concept-request-mode)
-pub enum RequestMode {
- SameOrigin,
- NoCORS,
- CORSMode,
- ForcedPreflightMode
-}
-
-/// Request [credentials mode](http://fetch.spec.whatwg.org/#concept-request-credentials-mode)
-pub enum CredentialsMode {
- Omit,
- CredentialsSameOrigin,
- Include
-}
-
-/// [Response tainting](http://fetch.spec.whatwg.org/#concept-request-response-tainting)
-pub enum ResponseTainting {
- Basic,
- CORSTainting,
- Opaque
-}
-
-/// A [Request](http://fetch.spec.whatwg.org/#requests) as defined by the Fetch spec
-pub struct Request {
- pub method: Method,
- pub url: Url,
- pub headers: HeaderCollection,
- pub unsafe_request: bool,
- pub body: Option<Vec<u8>>,
- pub preserve_content_codings: bool,
- // pub client: GlobalRef, // XXXManishearth copy over only the relevant fields of the global scope,
- // not the entire scope to avoid the libscript dependency
- pub skip_service_worker: bool,
- pub context: Context,
- pub context_frame_type: ContextFrameType,
- pub origin: Option<Url>,
- pub force_origin_header: bool,
- pub same_origin_data: bool,
- pub referer: Referer,
- pub authentication: bool,
- pub sync: bool,
- pub mode: RequestMode,
- pub credentials_mode: CredentialsMode,
- pub use_url_credentials: bool,
- pub manual_redirect: bool,
- pub redirect_count: uint,
- pub response_tainting: ResponseTainting,
- pub cache: Option<Box<CORSCache>>
-}
-
-impl Request {
- pub fn new(url: Url, context: Context) -> Request {
- Request {
- method: Get,
- url: url,
- headers: HeaderCollection::new(),
- unsafe_request: false,
- body: None,
- preserve_content_codings: false,
- skip_service_worker: false,
- context: context,
- context_frame_type: ContextNone,
- origin: None,
- force_origin_header: false,
- same_origin_data: false,
- referer: Client,
- authentication: false,
- sync: false,
- mode: NoCORS,
- credentials_mode: Omit,
- use_url_credentials: false,
- manual_redirect: false,
- redirect_count: 0,
- response_tainting: Basic,
- cache: None
- }
- }
-
- /// [Basic fetch](http://fetch.spec.whatwg.org#basic-fetch)
- pub fn basic_fetch(&mut self) -> Response {
- match self.url.scheme.as_slice() {
- "about" => match self.url.non_relative_scheme_data() {
- Some(s) if s.as_slice() == "blank" => {
- let mut response = Response::new();
- let _ = response.headers.insert_raw("Content-Type".to_string(), b"text/html;charset=utf-8");
- response
- },
- _ => Response::network_error()
- },
- "http" | "https" => {
- self.http_fetch(false, false, false)
- },
- "blob" | "data" | "file" | "ftp" => {
- // XXXManishearth handle these
- fail!("Unimplemented scheme for Fetch")
- },
-
- _ => Response::network_error()
- }
- }
-
- // [HTTP fetch](http://fetch.spec.whatwg.org#http-fetch)
- pub fn http_fetch(&mut self, _cors_flag: bool, cors_preflight_flag: bool, _authentication_fetch_flag: bool) -> Response {
- let response = Response::new();
- // TODO: Service worker fetch
- // Step 3
- // Substep 1
- self.skip_service_worker = true;
- // Substep 2
- if cors_preflight_flag {
- // XXXManishearth stuff goes here
- }
- response
- }
-}
diff --git a/src/components/net/fetch/response.rs b/src/components/net/fetch/response.rs
deleted file mode 100644
index 359ec6aa394..00000000000
--- a/src/components/net/fetch/response.rs
+++ /dev/null
@@ -1,144 +0,0 @@
-/* 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/. */
-
-use url::Url;
-use http::status::{Status, UnregisteredStatus};
-use StatusOk = http::status::Ok;
-use http::headers::HeaderEnum;
-use http::headers::response::HeaderCollection;
-use std::ascii::OwnedStrAsciiExt;
-use std::comm::Receiver;
-
-/// [Response type](http://fetch.spec.whatwg.org/#concept-response-type)
-#[deriving(Clone, PartialEq)]
-pub enum ResponseType {
- Basic,
- CORS,
- Default,
- Error,
- Opaque
-}
-
-/// [Response termination reason](http://fetch.spec.whatwg.org/#concept-response-termination-reason)
-#[deriving(Clone)]
-pub enum TerminationReason {
- EndUserAbort,
- Fatal,
- Timeout
-}
-
-/// The response body can still be pushed to after fetch
-/// This provides a way to store unfinished response bodies
-#[unstable = "I haven't yet decided exactly how the interface for this will be"]
-#[deriving(Clone)]
-pub enum ResponseBody {
- Empty, // XXXManishearth is this necessary, or is Done(vec![]) enough?
- Receiving(Vec<u8>),
- Done(Vec<u8>),
-}
-
-#[unstable = "I haven't yet decided exactly how the interface for this will be"]
-pub enum ResponseMsg {
- Chunk(Vec<u8>),
- Finished,
- Errored
-}
-
-#[unstable = "I haven't yet decided exactly how the interface for this will be"]
-pub struct ResponseLoader {
- response: Response,
- chan: Receiver<ResponseMsg>
-}
-
-/// A [Response](http://fetch.spec.whatwg.org/#concept-response) as defined by the Fetch spec
-#[deriving(Clone)]
-pub struct Response {
- pub response_type: ResponseType,
- pub termination_reason: Option<TerminationReason>,
- pub url: Option<Url>,
- pub status: Status,
- pub headers: HeaderCollection,
- pub body: ResponseBody,
- /// [Internal response](http://fetch.spec.whatwg.org/#concept-internal-response), only used if the Response is a filtered response
- pub internal_response: Option<Box<Response>>,
-}
-
-impl Response {
- pub fn new() -> Response {
- Response {
- response_type: Default,
- termination_reason: None,
- url: None,
- status: StatusOk,
- headers: HeaderCollection::new(),
- body: Empty,
- internal_response: None
- }
- }
-
- pub fn network_error() -> Response {
- Response {
- response_type: Error,
- termination_reason: None,
- url: None,
- status: UnregisteredStatus(0, "".to_string()),
- headers: HeaderCollection::new(),
- body: Empty,
- internal_response: None
- }
- }
-
- pub fn is_network_error(&self) -> bool {
- match self.response_type {
- Error => true,
- _ => false
- }
- }
-
- /// Convert to a filtered response, of type `filter_type`.
- /// Do not use with type Error or Default
- pub fn to_filtered(self, filter_type: ResponseType) -> Response {
- assert!(filter_type != Error);
- assert!(filter_type != Default);
- if self.is_network_error() {
- return self;
- }
- let old_headers = self.headers.clone();
- let mut response = self.clone();
- response.internal_response = Some(box self);
- match filter_type {
- Default | Error => unreachable!(),
- Basic => {
- let mut headers = HeaderCollection::new();
- for h in old_headers.iter() {
- match h.header_name().into_ascii_lower().as_slice() {
- "set-cookie" | "set-cookie2" => {},
- _ => headers.insert(h)
- }
- }
- response.headers = headers;
- response.response_type = filter_type;
- },
- CORS => {
- let mut headers = HeaderCollection::new();
- for h in old_headers.iter() {
- match h.header_name().into_ascii_lower().as_slice() {
- "cache-control" | "content-language" |
- "content-type" | "expires" | "last-modified" | "Pragma" => {},
- // XXXManishearth handle Access-Control-Expose-Headers
- _ => headers.insert(h)
- }
- }
- response.headers = headers;
- response.response_type = filter_type;
- },
- Opaque => {
- response.headers = HeaderCollection::new();
- response.status = UnregisteredStatus(0, "".to_string());
- response.body = Empty;
- }
- }
- response
- }
-}
diff --git a/src/components/net/file_loader.rs b/src/components/net/file_loader.rs
deleted file mode 100644
index 43c3191c600..00000000000
--- a/src/components/net/file_loader.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-/* 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/. */
-
-use resource_task::{ProgressMsg, Metadata, Payload, Done, LoaderTask, start_sending};
-
-use std::io;
-use std::io::File;
-use servo_util::task::spawn_named;
-
-static READ_SIZE: uint = 8192;
-
-fn read_all(reader: &mut io::Stream, progress_chan: &Sender<ProgressMsg>)
- -> Result<(), String> {
- loop {
- let mut buf = vec!();
- match reader.push_at_least(READ_SIZE, READ_SIZE, &mut buf) {
- Ok(_) => progress_chan.send(Payload(buf)),
- Err(e) => match e.kind {
- io::EndOfFile => {
- if buf.len() > 0 {
- progress_chan.send(Payload(buf));
- }
- return Ok(());
- }
- _ => return Err(e.desc.to_string()),
- }
- }
- }
-}
-
-pub fn factory() -> LoaderTask {
- let f: LoaderTask = proc(load_data, start_chan) {
- let url = load_data.url;
- assert!("file" == url.scheme.as_slice());
- let progress_chan = start_sending(start_chan, Metadata::default(url.clone()));
- spawn_named("file_loader", proc() {
- match File::open_mode(&Path::new(url.serialize_path().unwrap()), io::Open, io::Read) {
- Ok(ref mut reader) => {
- let res = read_all(reader as &mut io::Stream, &progress_chan);
- progress_chan.send(Done(res));
- }
- Err(e) => {
- progress_chan.send(Done(Err(e.desc.to_string())));
- }
- };
- });
- };
- f
-}
diff --git a/src/components/net/http_loader.rs b/src/components/net/http_loader.rs
deleted file mode 100644
index c7cb56d4231..00000000000
--- a/src/components/net/http_loader.rs
+++ /dev/null
@@ -1,167 +0,0 @@
-/* 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/. */
-
-use resource_task::{Metadata, Payload, Done, LoadResponse, LoadData, LoaderTask, start_sending_opt};
-
-use std::collections::hashmap::HashSet;
-use http::client::{RequestWriter, NetworkStream};
-use http::headers::HeaderEnum;
-use std::io::Reader;
-use servo_util::task::spawn_named;
-use url::Url;
-
-pub fn factory() -> LoaderTask {
- let f: LoaderTask = proc(url, start_chan) {
- spawn_named("http_loader", proc() load(url, start_chan))
- };
- f
-}
-
-fn send_error(url: Url, err: String, start_chan: Sender<LoadResponse>) {
- match start_sending_opt(start_chan, Metadata::default(url)) {
- Ok(p) => p.send(Done(Err(err))),
- _ => {}
- };
-}
-
-fn load(load_data: LoadData, start_chan: Sender<LoadResponse>) {
- // 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.
- let max_redirects = 50u;
- let mut iters = 0u;
- let mut url = load_data.url.clone();
- let mut redirected_to = HashSet::new();
-
- // Loop to handle redirects.
- loop {
- iters = iters + 1;
-
- if iters > max_redirects {
- send_error(url, "too many redirects".to_string(), start_chan);
- return;
- }
-
- if redirected_to.contains(&url) {
- send_error(url, "redirect loop".to_string(), start_chan);
- return;
- }
-
- redirected_to.insert(url.clone());
-
- match url.scheme.as_slice() {
- "http" | "https" => {}
- _ => {
- let s = format!("{:s} request, but we don't support that scheme", url.scheme);
- send_error(url, s, start_chan);
- return;
- }
- }
-
- info!("requesting {:s}", url.serialize());
-
- let request = RequestWriter::<NetworkStream>::new(load_data.method.clone(), url.clone());
- let mut writer = match request {
- Ok(w) => box w,
- Err(e) => {
- send_error(url, e.desc.to_string(), start_chan);
- return;
- }
- };
-
- // Preserve the `host` header set automatically by RequestWriter.
- let host = writer.headers.host.clone();
- writer.headers = box load_data.headers.clone();
- writer.headers.host = host;
- if writer.headers.accept_encoding.is_none() {
- // We currently don't support HTTP Compression (FIXME #2587)
- writer.headers.accept_encoding = Some(String::from_str("identity".as_slice()))
- }
- match load_data.data {
- Some(ref data) => {
- writer.headers.content_length = Some(data.len());
- match writer.write(data.as_slice()) {
- Err(e) => {
- send_error(url, e.desc.to_string(), start_chan);
- return;
- }
- _ => {}
- }
- },
- _ => {}
- }
- let mut response = match writer.read_response() {
- Ok(r) => r,
- Err((_, e)) => {
- send_error(url, e.desc.to_string(), start_chan);
- return;
- }
- };
-
- // Dump headers, but only do the iteration if info!() is enabled.
- info!("got HTTP response {:s}, headers:", response.status.to_string());
- info!("{:?}",
- for header in response.headers.iter() {
- info!(" - {:s}: {:s}", header.header_name(), header.header_value());
- });
-
- if 3 == (response.status.code() / 100) {
- match response.headers.location {
- Some(new_url) => {
- // CORS (http://fetch.spec.whatwg.org/#http-fetch, status section, point 9, 10)
- match load_data.cors {
- Some(ref c) => {
- if c.preflight {
- // The preflight lied
- send_error(url, "Preflight fetch inconsistent with main fetch".to_string(), start_chan);
- return;
- } else {
- // XXXManishearth There are some CORS-related steps here,
- // but they don't seem necessary until credentials are implemented
- }
- }
- _ => {}
- }
- info!("redirecting to {:s}", new_url.serialize());
- url = new_url;
- continue;
- }
- None => ()
- }
- }
-
- let mut metadata = Metadata::default(url);
- metadata.set_content_type(&response.headers.content_type);
- metadata.headers = Some(*response.headers.clone());
- metadata.status = response.status.clone();
-
- let progress_chan = match start_sending_opt(start_chan, metadata) {
- Ok(p) => p,
- _ => return
- };
- loop {
- let mut buf = Vec::with_capacity(1024);
-
- unsafe { buf.set_len(1024); }
- match response.read(buf.as_mut_slice()) {
- Ok(len) => {
- unsafe { buf.set_len(len); }
- if progress_chan.send_opt(Payload(buf)).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;
- }
- }
- Err(_) => {
- let _ = progress_chan.send_opt(Done(Ok(())));
- break;
- }
- }
- }
-
- // We didn't get redirected.
- break;
- }
-}
diff --git a/src/components/net/image/base.rs b/src/components/net/image/base.rs
deleted file mode 100644
index deda4ee8556..00000000000
--- a/src/components/net/image/base.rs
+++ /dev/null
@@ -1,67 +0,0 @@
-/* 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/. */
-
-use std::iter::range_step;
-use stb_image = stb_image::image;
-use png;
-
-// FIXME: Images must not be copied every frame. Instead we should atomically
-// reference count them.
-pub type Image = png::Image;
-
-
-static TEST_IMAGE: &'static [u8] = include_bin!("test.jpeg");
-
-pub fn test_image_bin() -> Vec<u8> {
- TEST_IMAGE.iter().map(|&x| x).collect()
-}
-
-// TODO(pcwalton): Speed up with SIMD, or better yet, find some way to not do this.
-fn byte_swap(data: &mut [u8]) {
- let length = data.len();
- for i in range_step(0, length, 4) {
- let r = data[i + 2];
- data[i + 2] = data[i + 0];
- data[i + 0] = r;
- }
-}
-
-pub fn load_from_memory(buffer: &[u8]) -> Option<Image> {
- if buffer.len() == 0 {
- return None;
- }
-
- if png::is_png(buffer) {
- match png::load_png_from_memory(buffer) {
- Ok(mut png_image) => {
- match png_image.pixels {
- png::RGB8(ref mut data) | png::RGBA8(ref mut data) => {
- byte_swap(data.as_mut_slice());
- }
- _ => {}
- }
- Some(png_image)
- }
- Err(_err) => None,
- }
- } else {
- // For non-png images, we use stb_image
- // Can't remember why we do this. Maybe it's what cairo wants
- static FORCE_DEPTH: uint = 4;
-
- match stb_image::load_from_memory_with_depth(buffer, FORCE_DEPTH, true) {
- stb_image::ImageU8(mut image) => {
- assert!(image.depth == 4);
- byte_swap(image.data.as_mut_slice());
- Some(png::Image {
- width: image.width as u32,
- height: image.height as u32,
- pixels: png::RGBA8(image.data)
- })
- }
- stb_image::ImageF32(_image) => fail!("HDR images not implemented"),
- stb_image::Error(_) => None
- }
- }
-}
diff --git a/src/components/net/image/holder.rs b/src/components/net/image/holder.rs
deleted file mode 100644
index 11f055aad9d..00000000000
--- a/src/components/net/image/holder.rs
+++ /dev/null
@@ -1,109 +0,0 @@
-/* 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/. */
-
-use image::base::Image;
-use image_cache_task::{ImageReady, ImageNotReady, ImageFailed};
-use local_image_cache::LocalImageCache;
-
-use geom::size::Size2D;
-use std::mem;
-use sync::{Arc, Mutex};
-use url::Url;
-
-// FIXME: Nasty coupling here This will be a problem if we want to factor out image handling from
-// the network stack. This should probably be factored out into an interface and use dependency
-// injection.
-
-/// A struct to store image data. The image will be loaded once the first time it is requested,
-/// and an Arc will be stored. Clones of this Arc are given out on demand.
-#[deriving(Clone)]
-pub struct ImageHolder {
- url: Url,
- image: Option<Arc<Box<Image>>>,
- cached_size: Size2D<int>,
- local_image_cache: Arc<Mutex<LocalImageCache>>,
-}
-
-impl ImageHolder {
- pub fn new(url: Url, local_image_cache: Arc<Mutex<LocalImageCache>>) -> ImageHolder {
- debug!("ImageHolder::new() {}", url.serialize());
- let holder = ImageHolder {
- url: url,
- image: None,
- cached_size: Size2D(0,0),
- local_image_cache: local_image_cache.clone(),
- };
-
- // Tell the image cache we're going to be interested in this url
- // FIXME: These two messages must be sent to prep an image for use
- // but they are intended to be spread out in time. Ideally prefetch
- // should be done as early as possible and decode only once we
- // are sure that the image will be used.
- {
- let val = holder.local_image_cache.lock();
- let mut local_image_cache = val;
- local_image_cache.prefetch(&holder.url);
- local_image_cache.decode(&holder.url);
- }
-
- holder
- }
-
- /// This version doesn't perform any computation, but may be stale w.r.t. newly-available image
- /// data that determines size.
- ///
- /// The intent is that the impure version is used during layout when dimensions are used for
- /// computing layout.
- pub fn size(&self) -> Size2D<int> {
- self.cached_size
- }
-
- /// Query and update the current image size.
- pub fn get_size(&mut self) -> Option<Size2D<int>> {
- debug!("get_size() {}", self.url.serialize());
- self.get_image().map(|img| {
- self.cached_size = Size2D(img.width as int,
- img.height as int);
- self.cached_size.clone()
- })
- }
-
- pub fn get_image_if_present(&self) -> Option<Arc<Box<Image>>> {
- debug!("get_image_if_present() {}", self.url.serialize());
- self.image.clone()
- }
-
- pub fn get_image(&mut self) -> Option<Arc<Box<Image>>> {
- debug!("get_image() {}", self.url.serialize());
-
- // If this is the first time we've called this function, load
- // the image and store it for the future
- if self.image.is_none() {
- let port = {
- let val = self.local_image_cache.lock();
- let mut local_image_cache = val;
- local_image_cache.get_image(&self.url)
- };
- match port.recv() {
- ImageReady(image) => {
- self.image = Some(image);
- }
- ImageNotReady => {
- debug!("image not ready for {:s}", self.url.serialize());
- }
- ImageFailed => {
- debug!("image decoding failed for {:s}", self.url.serialize());
- }
- }
- }
-
- // Clone isn't pure so we have to swap out the mutable image option
- let image = mem::replace(&mut self.image, None);
- let result = image.clone();
- mem::replace(&mut self.image, image);
-
- return result;
- }
-}
-
diff --git a/src/components/net/image/test.jpeg b/src/components/net/image/test.jpeg
deleted file mode 100644
index 1a0bdb7acd1..00000000000
--- a/src/components/net/image/test.jpeg
+++ /dev/null
Binary files differ
diff --git a/src/components/net/image_cache_task.rs b/src/components/net/image_cache_task.rs
deleted file mode 100644
index de0c978c3cf..00000000000
--- a/src/components/net/image_cache_task.rs
+++ /dev/null
@@ -1,993 +0,0 @@
-/* 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/. */
-
-use image::base::{Image, load_from_memory};
-use resource_task;
-use resource_task::{LoadData, ResourceTask};
-
-use std::comm::{channel, Receiver, Sender};
-use std::collections::hashmap::HashMap;
-use std::mem::replace;
-use std::task::spawn;
-use std::result;
-use sync::{Arc, Mutex};
-use serialize::{Encoder, Encodable};
-use url::Url;
-
-pub enum Msg {
- /// Tell the cache that we may need a particular image soon. Must be posted
- /// before Decode
- Prefetch(Url),
-
- /// Tell the cache to decode an image. Must be posted before GetImage/WaitForImage
- Decode(Url),
-
- /// Request an Image object for a URL. If the image is not is not immediately
- /// available then ImageNotReady is returned.
- GetImage(Url, Sender<ImageResponseMsg>),
-
- /// Wait for an image to become available (or fail to load).
- WaitForImage(Url, Sender<ImageResponseMsg>),
-
- /// Clients must wait for a response before shutting down the ResourceTask
- Exit(Sender<()>),
-
- /// Used by the prefetch tasks to post back image binaries
- StorePrefetchedImageData(Url, Result<Vec<u8>, ()>),
-
- /// Used by the decoder tasks to post decoded images back to the cache
- StoreImage(Url, Option<Arc<Box<Image>>>),
-
- /// For testing
- WaitForStore(Sender<()>),
-
- /// For testing
- WaitForStorePrefetched(Sender<()>),
-}
-
-#[deriving(Clone)]
-pub enum ImageResponseMsg {
- ImageReady(Arc<Box<Image>>),
- ImageNotReady,
- ImageFailed
-}
-
-impl PartialEq for ImageResponseMsg {
- fn eq(&self, other: &ImageResponseMsg) -> bool {
- match (self, other) {
- (&ImageReady(..), &ImageReady(..)) => fail!("unimplemented comparison"),
- (&ImageNotReady, &ImageNotReady) => true,
- (&ImageFailed, &ImageFailed) => true,
-
- (&ImageReady(..), _) | (&ImageNotReady, _) | (&ImageFailed, _) => false
- }
- }
-}
-
-#[deriving(Clone)]
-pub struct ImageCacheTask {
- chan: Sender<Msg>,
-}
-
-impl<E, S: Encoder<E>> Encodable<S, E> for ImageCacheTask {
- fn encode(&self, _: &mut S) -> Result<(), E> {
- Ok(())
- }
-}
-
-type DecoderFactory = fn() -> proc(&[u8]) -> Option<Image>;
-
-impl ImageCacheTask {
- pub fn new(resource_task: ResourceTask) -> ImageCacheTask {
- let (chan, port) = channel();
- let chan_clone = chan.clone();
-
- spawn(proc() {
- let mut cache = ImageCache {
- resource_task: resource_task,
- port: port,
- chan: chan_clone,
- state_map: HashMap::new(),
- wait_map: HashMap::new(),
- need_exit: None
- };
- cache.run();
- });
-
- ImageCacheTask {
- chan: chan,
- }
- }
-
- pub fn new_sync(resource_task: ResourceTask) -> ImageCacheTask {
- let (chan, port) = channel();
-
- spawn(proc() {
- let inner_cache = ImageCacheTask::new(resource_task);
-
- loop {
- let msg: Msg = port.recv();
-
- match msg {
- GetImage(url, response) => {
- inner_cache.send(WaitForImage(url, response));
- }
- Exit(response) => {
- inner_cache.send(Exit(response));
- break;
- }
- msg => inner_cache.send(msg)
- }
- }
- });
-
- ImageCacheTask {
- chan: chan,
- }
- }
-}
-
-struct ImageCache {
- /// A handle to the resource task for fetching the image binaries
- resource_task: ResourceTask,
- /// The port on which we'll receive client requests
- port: Receiver<Msg>,
- /// A copy of the shared chan to give to child tasks
- chan: Sender<Msg>,
- /// The state of processsing an image for a URL
- state_map: HashMap<Url, ImageState>,
- /// List of clients waiting on a WaitForImage response
- wait_map: HashMap<Url, Arc<Mutex<Vec<Sender<ImageResponseMsg>>>>>,
- need_exit: Option<Sender<()>>,
-}
-
-#[deriving(Clone)]
-enum ImageState {
- Init,
- Prefetching(AfterPrefetch),
- Prefetched(Vec<u8>),
- Decoding,
- Decoded(Arc<Box<Image>>),
- Failed
-}
-
-#[deriving(Clone)]
-enum AfterPrefetch {
- DoDecode,
- DoNotDecode
-}
-
-impl ImageCache {
- pub fn run(&mut self) {
- let mut store_chan: Option<Sender<()>> = None;
- let mut store_prefetched_chan: Option<Sender<()>> = None;
-
- loop {
- let msg = self.port.recv();
-
- debug!("image_cache_task: received: {:?}", msg);
-
- match msg {
- Prefetch(url) => self.prefetch(url),
- StorePrefetchedImageData(url, data) => {
- store_prefetched_chan.map(|chan| {
- chan.send(());
- });
- store_prefetched_chan = None;
-
- self.store_prefetched_image_data(url, data);
- }
- Decode(url) => self.decode(url),
- StoreImage(url, image) => {
- store_chan.map(|chan| {
- chan.send(());
- });
- store_chan = None;
-
- self.store_image(url, image)
- }
- GetImage(url, response) => self.get_image(url, response),
- WaitForImage(url, response) => {
- self.wait_for_image(url, response)
- }
- WaitForStore(chan) => store_chan = Some(chan),
- WaitForStorePrefetched(chan) => store_prefetched_chan = Some(chan),
- Exit(response) => {
- assert!(self.need_exit.is_none());
- self.need_exit = Some(response);
- }
- }
-
- let need_exit = replace(&mut self.need_exit, None);
-
- match need_exit {
- Some(response) => {
- // Wait until we have no outstanding requests and subtasks
- // before exiting
- let mut can_exit = true;
- for (_, state) in self.state_map.iter() {
- match *state {
- Prefetching(..) => can_exit = false,
- Decoding => can_exit = false,
-
- Init | Prefetched(..) | Decoded(..) | Failed => ()
- }
- }
-
- if can_exit {
- response.send(());
- break;
- } else {
- self.need_exit = Some(response);
- }
- }
- None => ()
- }
- }
- }
-
- fn get_state(&self, url: Url) -> ImageState {
- match self.state_map.find(&url) {
- Some(state) => state.clone(),
- None => Init
- }
- }
-
- fn set_state(&mut self, url: Url, state: ImageState) {
- self.state_map.insert(url, state);
- }
-
- fn prefetch(&mut self, url: Url) {
- match self.get_state(url.clone()) {
- Init => {
- let to_cache = self.chan.clone();
- let resource_task = self.resource_task.clone();
- let url_clone = url.clone();
-
- spawn(proc() {
- let url = url_clone;
- debug!("image_cache_task: started fetch for {:s}", url.serialize());
-
- let image = load_image_data(url.clone(), resource_task.clone());
-
- let result = if image.is_ok() {
- Ok(image.unwrap())
- } else {
- Err(())
- };
- to_cache.send(StorePrefetchedImageData(url.clone(), result));
- debug!("image_cache_task: ended fetch for {:s}", url.serialize());
- });
-
- self.set_state(url, Prefetching(DoNotDecode));
- }
-
- Prefetching(..) | Prefetched(..) | Decoding | Decoded(..) | Failed => {
- // We've already begun working on this image
- }
- }
- }
-
- fn store_prefetched_image_data(&mut self, url: Url, data: Result<Vec<u8>, ()>) {
- match self.get_state(url.clone()) {
- Prefetching(next_step) => {
- match data {
- Ok(data) => {
- self.set_state(url.clone(), Prefetched(data));
- match next_step {
- DoDecode => self.decode(url),
- _ => ()
- }
- }
- Err(..) => {
- self.set_state(url.clone(), Failed);
- self.purge_waiters(url, || ImageFailed);
- }
- }
- }
-
- Init
- | Prefetched(..)
- | Decoding
- | Decoded(..)
- | Failed => {
- fail!("wrong state for storing prefetched image")
- }
- }
- }
-
- fn decode(&mut self, url: Url) {
- match self.get_state(url.clone()) {
- Init => fail!("decoding image before prefetch"),
-
- Prefetching(DoNotDecode) => {
- // We don't have the data yet, queue up the decode
- self.set_state(url, Prefetching(DoDecode))
- }
-
- Prefetching(DoDecode) => {
- // We don't have the data yet, but the decode request is queued up
- }
-
- Prefetched(data) => {
- let to_cache = self.chan.clone();
- let url_clone = url.clone();
-
- spawn(proc() {
- let url = url_clone;
- debug!("image_cache_task: started image decode for {:s}", url.serialize());
- let image = load_from_memory(data.as_slice());
- let image = if image.is_some() {
- Some(Arc::new(box image.unwrap()))
- } else {
- None
- };
- to_cache.send(StoreImage(url.clone(), image));
- debug!("image_cache_task: ended image decode for {:s}", url.serialize());
- });
-
- self.set_state(url, Decoding);
- }
-
- Decoding | Decoded(..) | Failed => {
- // We've already begun decoding
- }
- }
- }
-
- fn store_image(&mut self, url: Url, image: Option<Arc<Box<Image>>>) {
-
- match self.get_state(url.clone()) {
- Decoding => {
- match image {
- Some(image) => {
- self.set_state(url.clone(), Decoded(image.clone()));
- self.purge_waiters(url, || ImageReady(image.clone()) );
- }
- None => {
- self.set_state(url.clone(), Failed);
- self.purge_waiters(url, || ImageFailed );
- }
- }
- }
-
- Init
- | Prefetching(..)
- | Prefetched(..)
- | Decoded(..)
- | Failed => {
- fail!("incorrect state in store_image")
- }
- }
-
- }
-
- fn purge_waiters(&mut self, url: Url, f: || -> ImageResponseMsg) {
- match self.wait_map.pop(&url) {
- Some(waiters) => {
- let mut items = waiters.lock();
- for response in items.iter() {
- response.send(f());
- }
- }
- None => ()
- }
- }
-
- fn get_image(&self, url: Url, response: Sender<ImageResponseMsg>) {
- match self.get_state(url.clone()) {
- Init => fail!("request for image before prefetch"),
- Prefetching(DoDecode) => response.send(ImageNotReady),
- Prefetching(DoNotDecode) | Prefetched(..) => fail!("request for image before decode"),
- Decoding => response.send(ImageNotReady),
- Decoded(image) => response.send(ImageReady(image.clone())),
- Failed => response.send(ImageFailed),
- }
- }
-
- fn wait_for_image(&mut self, url: Url, response: Sender<ImageResponseMsg>) {
- match self.get_state(url.clone()) {
- Init => fail!("request for image before prefetch"),
-
- Prefetching(DoNotDecode) | Prefetched(..) => fail!("request for image before decode"),
-
- Prefetching(DoDecode) | Decoding => {
- // We don't have this image yet
- if self.wait_map.contains_key(&url) {
- let waiters = self.wait_map.find_mut(&url).unwrap();
- let mut response = Some(response);
- let mut items = waiters.lock();
- items.push(response.take().unwrap());
- } else {
- let response = vec!(response);
- let wrapped = Arc::new(Mutex::new(response));
- self.wait_map.insert(url, wrapped);
- }
- }
-
- Decoded(image) => {
- response.send(ImageReady(image.clone()));
- }
-
- Failed => {
- response.send(ImageFailed);
- }
- }
- }
-
-}
-
-
-pub trait ImageCacheTaskClient {
- fn exit(&self);
-}
-
-impl ImageCacheTaskClient for ImageCacheTask {
- fn exit(&self) {
- let (response_chan, response_port) = channel();
- self.send(Exit(response_chan));
- response_port.recv();
- }
-}
-
-impl ImageCacheTask {
- pub fn send(&self, msg: Msg) {
- self.chan.send(msg);
- }
-
- #[cfg(test)]
- fn wait_for_store(&self) -> Receiver<()> {
- let (chan, port) = channel();
- self.send(WaitForStore(chan));
- port
- }
-
- #[cfg(test)]
- fn wait_for_store_prefetched(&self) -> Receiver<()> {
- let (chan, port) = channel();
- self.send(WaitForStorePrefetched(chan));
- port
- }
-}
-
-fn load_image_data(url: Url, resource_task: ResourceTask) -> Result<Vec<u8>, ()> {
- let (response_chan, response_port) = channel();
- resource_task.send(resource_task::Load(LoadData::new(url), response_chan));
-
- let mut image_data = vec!();
-
- let progress_port = response_port.recv().progress_port;
- loop {
- match progress_port.recv() {
- resource_task::Payload(data) => {
- image_data.push_all(data.as_slice());
- }
- resource_task::Done(result::Ok(..)) => {
- return Ok(image_data.move_iter().collect());
- }
- resource_task::Done(result::Err(..)) => {
- return Err(());
- }
- }
- }
-}
-
-
-pub fn spawn_listener<A: Send>(f: proc(Receiver<A>):Send) -> Sender<A> {
- let (setup_chan, setup_port) = channel();
-
- spawn(proc() {
- let (chan, port) = channel();
- setup_chan.send(chan);
- f(port);
- });
- setup_port.recv()
-}
-
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- use resource_task;
- use resource_task::{ResourceTask, Metadata, start_sending};
- use image::base::test_image_bin;
- use std::comm;
- use url::Url;
-
- trait Closure {
- fn invoke(&self, _response: Sender<resource_task::ProgressMsg>) { }
- }
- struct DoesNothing;
- impl Closure for DoesNothing { }
-
- struct JustSendOK {
- url_requested_chan: Sender<()>,
- }
- impl Closure for JustSendOK {
- fn invoke(&self, response: Sender<resource_task::ProgressMsg>) {
- self.url_requested_chan.send(());
- response.send(resource_task::Done(Ok(())));
- }
- }
-
- struct SendTestImage;
- impl Closure for SendTestImage {
- fn invoke(&self, response: Sender<resource_task::ProgressMsg>) {
- response.send(resource_task::Payload(test_image_bin()));
- response.send(resource_task::Done(Ok(())));
- }
- }
-
- struct SendBogusImage;
- impl Closure for SendBogusImage {
- fn invoke(&self, response: Sender<resource_task::ProgressMsg>) {
- response.send(resource_task::Payload(vec!()));
- response.send(resource_task::Done(Ok(())));
- }
- }
-
- struct SendTestImageErr;
- impl Closure for SendTestImageErr {
- fn invoke(&self, response: Sender<resource_task::ProgressMsg>) {
- response.send(resource_task::Payload(test_image_bin()));
- response.send(resource_task::Done(Err("".to_string())));
- }
- }
-
- struct WaitSendTestImage {
- wait_port: Receiver<()>,
- }
- impl Closure for WaitSendTestImage {
- fn invoke(&self, response: Sender<resource_task::ProgressMsg>) {
- // Don't send the data until after the client requests
- // the image
- self.wait_port.recv();
- response.send(resource_task::Payload(test_image_bin()));
- response.send(resource_task::Done(Ok(())));
- }
- }
-
- struct WaitSendTestImageErr {
- wait_port: Receiver<()>,
- }
- impl Closure for WaitSendTestImageErr {
- fn invoke(&self, response: Sender<resource_task::ProgressMsg>) {
- // Don't send the data until after the client requests
- // the image
- self.wait_port.recv();
- response.send(resource_task::Payload(test_image_bin()));
- response.send(resource_task::Done(Err("".to_string())));
- }
- }
-
- fn mock_resource_task<T: Closure+Send>(on_load: Box<T>) -> ResourceTask {
- spawn_listener(proc(port: Receiver<resource_task::ControlMsg>) {
- loop {
- match port.recv() {
- resource_task::Load(_, response) => {
- let chan = start_sending(response, Metadata::default(
- Url::parse("file:///fake").unwrap()));
- on_load.invoke(chan);
- }
- resource_task::Exit => break
- }
- }
- })
- }
-
- #[test]
- fn should_exit_on_request() {
- let mock_resource_task = mock_resource_task(box DoesNothing);
-
- let image_cache_task = ImageCacheTask::new(mock_resource_task.clone());
-
- image_cache_task.exit();
- mock_resource_task.send(resource_task::Exit);
- }
-
- #[test]
- #[should_fail]
- fn should_fail_if_unprefetched_image_is_requested() {
- let mock_resource_task = mock_resource_task(box DoesNothing);
-
- let image_cache_task = ImageCacheTask::new(mock_resource_task.clone());
- let url = Url::parse("file:///").unwrap();
-
- let (chan, port) = channel();
- image_cache_task.send(GetImage(url, chan));
- port.recv();
- }
-
- #[test]
- fn should_request_url_from_resource_task_on_prefetch() {
- let (url_requested_chan, url_requested) = channel();
-
- let mock_resource_task = mock_resource_task(box JustSendOK { url_requested_chan: url_requested_chan});
-
- let image_cache_task = ImageCacheTask::new(mock_resource_task.clone());
- let url = Url::parse("file:///").unwrap();
-
- image_cache_task.send(Prefetch(url));
- url_requested.recv();
- image_cache_task.exit();
- mock_resource_task.send(resource_task::Exit);
- }
-
- #[test]
- fn should_not_request_url_from_resource_task_on_multiple_prefetches() {
- let (url_requested_chan, url_requested) = comm::channel();
-
- let mock_resource_task = mock_resource_task(box JustSendOK { url_requested_chan: url_requested_chan});
-
- let image_cache_task = ImageCacheTask::new(mock_resource_task.clone());
- let url = Url::parse("file:///").unwrap();
-
- image_cache_task.send(Prefetch(url.clone()));
- image_cache_task.send(Prefetch(url));
- url_requested.recv();
- image_cache_task.exit();
- mock_resource_task.send(resource_task::Exit);
- match url_requested.try_recv() {
- Err(_) => (),
- Ok(_) => fail!(),
- };
- }
-
- #[test]
- fn should_return_image_not_ready_if_data_has_not_arrived() {
- let (wait_chan, wait_port) = comm::channel();
-
- let mock_resource_task = mock_resource_task(box WaitSendTestImage{wait_port: wait_port});
-
- let image_cache_task = ImageCacheTask::new(mock_resource_task.clone());
- let url = Url::parse("file:///").unwrap();
-
- image_cache_task.send(Prefetch(url.clone()));
- image_cache_task.send(Decode(url.clone()));
- let (response_chan, response_port) = comm::channel();
- image_cache_task.send(GetImage(url, response_chan));
- assert!(response_port.recv() == ImageNotReady);
- wait_chan.send(());
- image_cache_task.exit();
- mock_resource_task.send(resource_task::Exit);
- }
-
- #[test]
- fn should_return_decoded_image_data_if_data_has_arrived() {
- let mock_resource_task = mock_resource_task(box SendTestImage);
-
- let image_cache_task = ImageCacheTask::new(mock_resource_task.clone());
- let url = Url::parse("file:///").unwrap();
-
- let join_port = image_cache_task.wait_for_store();
-
- image_cache_task.send(Prefetch(url.clone()));
- image_cache_task.send(Decode(url.clone()));
-
- // Wait until our mock resource task has sent the image to the image cache
- join_port.recv();
-
- let (response_chan, response_port) = comm::channel();
- image_cache_task.send(GetImage(url, response_chan));
- match response_port.recv() {
- ImageReady(_) => (),
- _ => fail!("bleh")
- }
-
- image_cache_task.exit();
- mock_resource_task.send(resource_task::Exit);
- }
-
- #[test]
- fn should_return_decoded_image_data_for_multiple_requests() {
- let mock_resource_task = mock_resource_task(box SendTestImage);
-
- let image_cache_task = ImageCacheTask::new(mock_resource_task.clone());
- let url = Url::parse("file:///").unwrap();
-
- let join_port = image_cache_task.wait_for_store();
-
- image_cache_task.send(Prefetch(url.clone()));
- image_cache_task.send(Decode(url.clone()));
-
- // Wait until our mock resource task has sent the image to the image cache
- join_port.recv();
-
- for _ in range(0u32, 2u32) {
- let (response_chan, response_port) = comm::channel();
- image_cache_task.send(GetImage(url.clone(), response_chan));
- match response_port.recv() {
- ImageReady(_) => (),
- _ => fail!("bleh")
- }
- }
-
- image_cache_task.exit();
- mock_resource_task.send(resource_task::Exit);
- }
-
- #[test]
- fn should_not_request_image_from_resource_task_if_image_is_already_available() {
- let (image_bin_sent_chan, image_bin_sent) = comm::channel();
-
- let (resource_task_exited_chan, resource_task_exited) = comm::channel();
-
- let mock_resource_task = spawn_listener(proc(port: Receiver<resource_task::ControlMsg>) {
- loop {
- match port.recv() {
- resource_task::Load(_, response) => {
- let chan = start_sending(response, Metadata::default(
- Url::parse("file:///fake").unwrap()));
- chan.send(resource_task::Payload(test_image_bin()));
- chan.send(resource_task::Done(Ok(())));
- image_bin_sent_chan.send(());
- }
- resource_task::Exit => {
- resource_task_exited_chan.send(());
- break
- }
- }
- }
- });
-
- let image_cache_task = ImageCacheTask::new(mock_resource_task.clone());
- let url = Url::parse("file:///").unwrap();
-
- image_cache_task.send(Prefetch(url.clone()));
-
- // Wait until our mock resource task has sent the image to the image cache
- image_bin_sent.recv();
-
- image_cache_task.send(Prefetch(url.clone()));
-
- image_cache_task.exit();
- mock_resource_task.send(resource_task::Exit);
-
- resource_task_exited.recv();
-
- // Our resource task should not have received another request for the image
- // because it's already cached
- match image_bin_sent.try_recv() {
- Err(_) => (),
- Ok(_) => fail!(),
- }
- }
-
- #[test]
- fn should_not_request_image_from_resource_task_if_image_fetch_already_failed() {
- let (image_bin_sent_chan, image_bin_sent) = comm::channel();
-
- let (resource_task_exited_chan, resource_task_exited) = comm::channel();
-
- let mock_resource_task = spawn_listener(proc(port: Receiver<resource_task::ControlMsg>) {
- loop {
- match port.recv() {
- resource_task::Load(_, response) => {
- let chan = start_sending(response, Metadata::default(
- Url::parse("file:///fake").unwrap()));
- chan.send(resource_task::Payload(test_image_bin()));
- chan.send(resource_task::Done(Err("".to_string())));
- image_bin_sent_chan.send(());
- }
- resource_task::Exit => {
- resource_task_exited_chan.send(());
- break
- }
- }
- }
- });
-
- let image_cache_task = ImageCacheTask::new(mock_resource_task.clone());
- let url = Url::parse("file:///").unwrap();
-
- image_cache_task.send(Prefetch(url.clone()));
- image_cache_task.send(Decode(url.clone()));
-
- // Wait until our mock resource task has sent the image to the image cache
- image_bin_sent.recv();
-
- image_cache_task.send(Prefetch(url.clone()));
- image_cache_task.send(Decode(url.clone()));
-
- image_cache_task.exit();
- mock_resource_task.send(resource_task::Exit);
-
- resource_task_exited.recv();
-
- // Our resource task should not have received another request for the image
- // because it's already cached
- match image_bin_sent.try_recv() {
- Err(_) => (),
- Ok(_) => fail!(),
- }
- }
-
- #[test]
- fn should_return_failed_if_image_bin_cannot_be_fetched() {
- let mock_resource_task = mock_resource_task(box SendTestImageErr);
-
- let image_cache_task = ImageCacheTask::new(mock_resource_task.clone());
- let url = Url::parse("file:///").unwrap();
-
- let join_port = image_cache_task.wait_for_store_prefetched();
-
- image_cache_task.send(Prefetch(url.clone()));
- image_cache_task.send(Decode(url.clone()));
-
- // Wait until our mock resource task has sent the image to the image cache
- join_port.recv();
-
- let (response_chan, response_port) = comm::channel();
- image_cache_task.send(GetImage(url, response_chan));
- match response_port.recv() {
- ImageFailed => (),
- _ => fail!("bleh")
- }
-
- image_cache_task.exit();
- mock_resource_task.send(resource_task::Exit);
- }
-
- #[test]
- fn should_return_failed_for_multiple_get_image_requests_if_image_bin_cannot_be_fetched() {
- let mock_resource_task = mock_resource_task(box SendTestImageErr);
-
- let image_cache_task = ImageCacheTask::new(mock_resource_task.clone());
- let url = Url::parse("file:///").unwrap();
-
- let join_port = image_cache_task.wait_for_store_prefetched();
-
- image_cache_task.send(Prefetch(url.clone()));
- image_cache_task.send(Decode(url.clone()));
-
- // Wait until our mock resource task has sent the image to the image cache
- join_port.recv();
-
- let (response_chan, response_port) = comm::channel();
- image_cache_task.send(GetImage(url.clone(), response_chan));
- match response_port.recv() {
- ImageFailed => (),
- _ => fail!("bleh")
- }
-
- // And ask again, we should get the same response
- let (response_chan, response_port) = comm::channel();
- image_cache_task.send(GetImage(url, response_chan));
- match response_port.recv() {
- ImageFailed => (),
- _ => fail!("bleh")
- }
-
- image_cache_task.exit();
- mock_resource_task.send(resource_task::Exit);
- }
-
- #[test]
- fn should_return_failed_if_image_decode_fails() {
- let mock_resource_task = mock_resource_task(box SendBogusImage);
-
- let image_cache_task = ImageCacheTask::new(mock_resource_task.clone());
- let url = Url::parse("file:///").unwrap();
-
- let join_port = image_cache_task.wait_for_store();
-
- image_cache_task.send(Prefetch(url.clone()));
- image_cache_task.send(Decode(url.clone()));
-
- // Wait until our mock resource task has sent the image to the image cache
- join_port.recv();
-
- // Make the request
- let (response_chan, response_port) = comm::channel();
- image_cache_task.send(GetImage(url, response_chan));
-
- match response_port.recv() {
- ImageFailed => (),
- _ => fail!("bleh")
- }
-
- image_cache_task.exit();
- mock_resource_task.send(resource_task::Exit);
- }
-
- #[test]
- fn should_return_image_on_wait_if_image_is_already_loaded() {
- let mock_resource_task = mock_resource_task(box SendTestImage);
-
- let image_cache_task = ImageCacheTask::new(mock_resource_task.clone());
- let url = Url::parse("file:///").unwrap();
-
- let join_port = image_cache_task.wait_for_store();
-
- image_cache_task.send(Prefetch(url.clone()));
- image_cache_task.send(Decode(url.clone()));
-
- // Wait until our mock resource task has sent the image to the image cache
- join_port.recv();
-
- let (response_chan, response_port) = comm::channel();
- image_cache_task.send(WaitForImage(url, response_chan));
- match response_port.recv() {
- ImageReady(..) => (),
- _ => fail!("bleh")
- }
-
- image_cache_task.exit();
- mock_resource_task.send(resource_task::Exit);
- }
-
- #[test]
- fn should_return_image_on_wait_if_image_is_not_yet_loaded() {
- let (wait_chan, wait_port) = comm::channel();
-
- let mock_resource_task = mock_resource_task(box WaitSendTestImage {wait_port: wait_port});
-
- let image_cache_task = ImageCacheTask::new(mock_resource_task.clone());
- let url = Url::parse("file:///").unwrap();
-
- image_cache_task.send(Prefetch(url.clone()));
- image_cache_task.send(Decode(url.clone()));
-
- let (response_chan, response_port) = comm::channel();
- image_cache_task.send(WaitForImage(url, response_chan));
-
- wait_chan.send(());
-
- match response_port.recv() {
- ImageReady(..) => (),
- _ => fail!("bleh")
- }
-
- image_cache_task.exit();
- mock_resource_task.send(resource_task::Exit);
- }
-
- #[test]
- fn should_return_image_failed_on_wait_if_image_fails_to_load() {
- let (wait_chan, wait_port) = comm::channel();
-
- let mock_resource_task = mock_resource_task(box WaitSendTestImageErr{wait_port: wait_port});
-
- let image_cache_task = ImageCacheTask::new(mock_resource_task.clone());
- let url = Url::parse("file:///").unwrap();
-
- image_cache_task.send(Prefetch(url.clone()));
- image_cache_task.send(Decode(url.clone()));
-
- let (response_chan, response_port) = comm::channel();
- image_cache_task.send(WaitForImage(url, response_chan));
-
- wait_chan.send(());
-
- match response_port.recv() {
- ImageFailed => (),
- _ => fail!("bleh")
- }
-
- image_cache_task.exit();
- mock_resource_task.send(resource_task::Exit);
- }
-
- #[test]
- fn sync_cache_should_wait_for_images() {
- let mock_resource_task = mock_resource_task(box SendTestImage);
-
- let image_cache_task = ImageCacheTask::new_sync(mock_resource_task.clone());
- let url = Url::parse("file:///").unwrap();
-
- image_cache_task.send(Prefetch(url.clone()));
- image_cache_task.send(Decode(url.clone()));
-
- let (response_chan, response_port) = comm::channel();
- image_cache_task.send(GetImage(url, response_chan));
- match response_port.recv() {
- ImageReady(_) => (),
- _ => fail!("bleh")
- }
-
- image_cache_task.exit();
- mock_resource_task.send(resource_task::Exit);
- }
-}
diff --git a/src/components/net/local_image_cache.rs b/src/components/net/local_image_cache.rs
deleted file mode 100644
index 1427c831654..00000000000
--- a/src/components/net/local_image_cache.rs
+++ /dev/null
@@ -1,166 +0,0 @@
-/* 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/. */
-
-/*!
-An adapter for ImageCacheTask that does local caching to avoid
-extra message traffic, it also avoids waiting on the same image
-multiple times and thus triggering reflows multiple times.
-*/
-
-use image_cache_task::{Decode, GetImage, ImageCacheTask, ImageFailed, ImageNotReady, ImageReady};
-use image_cache_task::{ImageResponseMsg, Prefetch, WaitForImage};
-
-use std::comm::{Receiver, channel};
-use std::collections::hashmap::HashMap;
-use servo_util::task::spawn_named;
-use url::Url;
-
-pub trait ImageResponder {
- fn respond(&self) -> proc(ImageResponseMsg):Send;
-}
-
-pub struct LocalImageCache {
- image_cache_task: ImageCacheTask,
- round_number: uint,
- on_image_available: Option<Box<ImageResponder+Send>>,
- state_map: HashMap<Url, ImageState>
-}
-
-impl LocalImageCache {
- pub fn new(image_cache_task: ImageCacheTask) -> LocalImageCache {
- LocalImageCache {
- image_cache_task: image_cache_task,
- round_number: 1,
- on_image_available: None,
- state_map: HashMap::new()
- }
- }
-}
-
-#[deriving(Clone)]
-struct ImageState {
- prefetched: bool,
- decoded: bool,
- last_request_round: uint,
- last_response: ImageResponseMsg
-}
-
-impl LocalImageCache {
- /// The local cache will only do a single remote request for a given
- /// URL in each 'round'. Layout should call this each time it begins
- pub fn next_round(&mut self, on_image_available: Box<ImageResponder+Send>) {
- self.round_number += 1;
- self.on_image_available = Some(on_image_available);
- }
-
- pub fn prefetch(&mut self, url: &Url) {
- {
- let state = self.get_state(url);
- if state.prefetched {
- return
- }
-
- state.prefetched = true;
- }
-
- self.image_cache_task.send(Prefetch((*url).clone()));
- }
-
- pub fn decode(&mut self, url: &Url) {
- {
- let state = self.get_state(url);
- if state.decoded {
- return
- }
- state.decoded = true;
- }
-
- self.image_cache_task.send(Decode((*url).clone()));
- }
-
- // FIXME: Should return a Future
- pub fn get_image(&mut self, url: &Url) -> Receiver<ImageResponseMsg> {
- {
- let round_number = self.round_number;
- let state = self.get_state(url);
-
- // Save the previous round number for comparison
- let last_round = state.last_request_round;
- // Set the current round number for this image
- state.last_request_round = round_number;
-
- match state.last_response {
- ImageReady(ref image) => {
- let (chan, port) = channel();
- chan.send(ImageReady(image.clone()));
- return port;
- }
- ImageNotReady => {
- if last_round == round_number {
- let (chan, port) = channel();
- chan.send(ImageNotReady);
- return port;
- } else {
- // We haven't requested the image from the
- // remote cache this round
- }
- }
- ImageFailed => {
- let (chan, port) = channel();
- chan.send(ImageFailed);
- return port;
- }
- }
- }
-
- let (response_chan, response_port) = channel();
- self.image_cache_task.send(GetImage((*url).clone(), response_chan));
-
- let response = response_port.recv();
- match response {
- ImageNotReady => {
- // Need to reflow when the image is available
- // FIXME: Instead we should be just passing a Future
- // to the caller, then to the display list. Finally,
- // the compositor should be resonsible for waiting
- // on the image to load and triggering layout
- let image_cache_task = self.image_cache_task.clone();
- assert!(self.on_image_available.is_some());
- let on_image_available: proc(ImageResponseMsg):Send = self.on_image_available.as_ref().unwrap().respond();
- let url = (*url).clone();
- spawn_named("LocalImageCache", proc() {
- let (response_chan, response_port) = channel();
- image_cache_task.send(WaitForImage(url.clone(), response_chan));
- on_image_available(response_port.recv());
- });
- }
- _ => ()
- }
-
- // Put a copy of the response in the cache
- let response_copy = match response {
- ImageReady(ref image) => ImageReady(image.clone()),
- ImageNotReady => ImageNotReady,
- ImageFailed => ImageFailed
- };
- self.get_state(url).last_response = response_copy;
-
- let (chan, port) = channel();
- chan.send(response);
- return port;
- }
-
- fn get_state<'a>(&'a mut self, url: &Url) -> &'a mut ImageState {
- let state = self.state_map.find_or_insert_with(url.clone(), |_| {
- let new_state = ImageState {
- prefetched: false,
- decoded: false,
- last_request_round: 0,
- last_response: ImageNotReady
- };
- new_state
- });
- state
- }
-}
diff --git a/src/components/net/net.rs b/src/components/net/net.rs
deleted file mode 100644
index 94290bdd7ff..00000000000
--- a/src/components/net/net.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-/* 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/. */
-
-#![crate_name = "net"]
-#![crate_type = "rlib"]
-
-#![feature(default_type_params, globs, managed_boxes, phase)]
-
-extern crate debug;
-extern crate collections;
-extern crate geom;
-extern crate http;
-extern crate png;
-#[phase(plugin, link)]
-extern crate log;
-extern crate serialize;
-extern crate servo_util = "util";
-extern crate stb_image;
-extern crate sync;
-extern crate time;
-extern crate url;
-
-/// 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;
-}
-
-pub mod file_loader;
-pub mod http_loader;
-pub mod data_loader;
-pub mod image_cache_task;
-pub mod local_image_cache;
-pub mod resource_task;
-
-/// An implementation of the [Fetch spec](http://fetch.spec.whatwg.org/)
-pub mod fetch {
- #![allow(dead_code)] // XXXManishearth this is only temporary until the Fetch mod starts being used
- pub mod request;
- pub mod response;
- pub mod cors_cache;
-}
diff --git a/src/components/net/resource_task.rs b/src/components/net/resource_task.rs
deleted file mode 100644
index bdc1c3f2339..00000000000
--- a/src/components/net/resource_task.rs
+++ /dev/null
@@ -1,267 +0,0 @@
-/* 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/. */
-
-//! A task that takes a URL and streams back the binary data.
-
-use file_loader;
-use http_loader;
-use data_loader;
-
-use std::comm::{channel, Receiver, Sender};
-use std::task::TaskBuilder;
-use std::os;
-use http::headers::content_type::MediaType;
-use ResponseHeaderCollection = http::headers::response::HeaderCollection;
-use RequestHeaderCollection = http::headers::request::HeaderCollection;
-use http::method::{Method, Get};
-use url::Url;
-
-use StatusOk = http::status::Ok;
-use http::status::Status;
-
-
-pub enum ControlMsg {
- /// Request the data associated with a particular URL
- Load(LoadData, Sender<LoadResponse>),
- Exit
-}
-
-#[deriving(Clone)]
-pub struct LoadData {
- pub url: Url,
- pub method: Method,
- pub headers: RequestHeaderCollection,
- pub data: Option<Vec<u8>>,
- pub cors: Option<ResourceCORSData>
-}
-
-impl LoadData {
- pub fn new(url: Url) -> LoadData {
- LoadData {
- url: url,
- method: Get,
- headers: RequestHeaderCollection::new(),
- data: None,
- cors: None
- }
- }
-}
-
-#[deriving(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.
-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<ResponseHeaderCollection>,
-
- /// HTTP Status
- pub status: Status
-}
-
-impl Metadata {
- /// Metadata with defaults for everything optional.
- pub fn default(url: Url) -> Metadata {
- Metadata {
- final_url: url,
- content_type: None,
- charset: None,
- headers: None,
- status: StatusOk // http://fetch.spec.whatwg.org/#concept-response-status-message
- }
- }
-
- /// Extract the parts of a MediaType that we care about.
- pub fn set_content_type(&mut self, content_type: &Option<MediaType>) {
- match *content_type {
- None => (),
- Some(MediaType { type_: ref type_,
- subtype: ref subtype,
- parameters: ref parameters }) => {
- self.content_type = Some((type_.clone(), subtype.clone()));
- for &(ref k, ref v) in parameters.iter() {
- if "charset" == k.as_slice() {
- self.charset = Some(v.clone());
- }
- }
- }
- }
- }
-}
-
-/// 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>,
-}
-
-/// Messages sent in response to a `Load` message
-#[deriving(PartialEq,Show)]
-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>)
-}
-
-/// For use by loaders in responding to a Load message.
-pub fn start_sending(start_chan: Sender<LoadResponse>, metadata: Metadata) -> Sender<ProgressMsg> {
- start_sending_opt(start_chan, metadata).ok().unwrap()
-}
-
-/// For use by loaders in responding to a Load message.
-pub fn start_sending_opt(start_chan: Sender<LoadResponse>, metadata: Metadata) -> Result<Sender<ProgressMsg>, ()> {
- let (progress_chan, progress_port) = channel();
- let result = start_chan.send_opt(LoadResponse {
- metadata: metadata,
- progress_port: progress_port,
- });
- match result {
- Ok(_) => Ok(progress_chan),
- Err(_) => Err(())
- }
-}
-
-/// 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(Load(LoadData::new(url), start_chan));
- let response = start_port.recv();
-
- let mut buf = vec!();
- loop {
- match response.progress_port.recv() {
- Payload(data) => buf.push_all(data.as_slice()),
- Done(Ok(())) => return Ok((response.metadata, buf)),
- Done(Err(e)) => return Err(e)
- }
- }
-}
-
-/// Handle to a resource task
-pub type ResourceTask = Sender<ControlMsg>;
-
-pub type LoaderTask = proc(load_data: LoadData, Sender<LoadResponse>);
-
-/**
-Creates a task to load a specific resource
-
-The ResourceManager delegates loading to a different type of loader task for
-each URL scheme
-*/
-type LoaderTaskFactory = extern "Rust" fn() -> LoaderTask;
-
-/// Create a ResourceTask
-pub fn new_resource_task() -> ResourceTask {
- let (setup_chan, setup_port) = channel();
- let builder = TaskBuilder::new().named("ResourceManager");
- builder.spawn(proc() {
- ResourceManager::new(setup_port).start();
- });
- setup_chan
-}
-
-struct ResourceManager {
- from_client: Receiver<ControlMsg>,
-}
-
-
-impl ResourceManager {
- fn new(from_client: Receiver<ControlMsg>) -> ResourceManager {
- ResourceManager {
- from_client : from_client,
- }
- }
-}
-
-
-impl ResourceManager {
- fn start(&self) {
- loop {
- match self.from_client.recv() {
- Load(load_data, start_chan) => {
- self.load(load_data, start_chan)
- }
- Exit => {
- break
- }
- }
- }
- }
-
- fn load(&self, mut load_data: LoadData, start_chan: Sender<LoadResponse>) {
- let loader = match load_data.url.scheme.as_slice() {
- "file" => file_loader::factory(),
- "http" | "https" => http_loader::factory(),
- "data" => data_loader::factory(),
- "about" => {
- match load_data.url.non_relative_scheme_data().unwrap() {
- "crash" => fail!("Loading the about:crash URL."),
- "failure" => {
- // FIXME: Find a way to load this without relying on the `../src` directory.
- let mut path = os::self_exe_path().expect("can't get exe path");
- path.pop();
- path.push_many(["src", "test", "html", "failure.html"]);
- load_data.url = Url::from_file_path(&path).unwrap();
- file_loader::factory()
- }
- _ => {
- start_sending(start_chan, Metadata::default(load_data.url))
- .send(Done(Err("Unknown about: URL.".to_string())));
- return
- }
- }
- },
- _ => {
- debug!("resource_task: no loader for scheme {:s}", load_data.url.scheme);
- start_sending(start_chan, Metadata::default(load_data.url))
- .send(Done(Err("no loader for scheme".to_string())));
- return
- }
- };
- debug!("resource_task: loading url: {:s}", load_data.url.serialize());
- loader(load_data, start_chan);
- }
-}
-
-#[test]
-fn test_exit() {
- let resource_task = new_resource_task();
- resource_task.send(Exit);
-}
-
-#[test]
-fn test_bad_scheme() {
- let resource_task = new_resource_task();
- let (start_chan, start) = channel();
- let url = Url::parse("bogus://whatever").unwrap();
- resource_task.send(Load(LoadData::new(url), start_chan));
- let response = start.recv();
- match response.progress_port.recv() {
- Done(result) => { assert!(result.is_err()) }
- _ => fail!("bleh")
- }
- resource_task.send(Exit);
-}