From 8cd572de958864f5ec964d676ffd06757722b800 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sat, 23 Aug 2014 12:13:59 +0530 Subject: [PATCH 1/4] Add basic_fetch and a skeleton http_fetch --- src/components/net/fetch/request.rs | 38 ++++++++++++++++++++++ src/components/net/fetch/response.rs | 48 ++++++++++++++++++++++++---- 2 files changed, 80 insertions(+), 6 deletions(-) diff --git a/src/components/net/fetch/request.rs b/src/components/net/fetch/request.rs index 2de606a1a31..2dfd5572a97 100644 --- a/src/components/net/fetch/request.rs +++ b/src/components/net/fetch/request.rs @@ -5,6 +5,7 @@ use url::Url; use http::method::{Get, Method}; use http::headers::request::HeaderCollection; +use fetch::response::Response; /// A [request context](http://fetch.spec.whatwg.org/#concept-request-context) pub enum Context { @@ -105,4 +106,41 @@ impl Request { response_tainting: Basic } } + + /// [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() + } + } + // [Basic 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 index ee98f388f7b..359ec6aa394 100644 --- a/src/components/net/fetch/response.rs +++ b/src/components/net/fetch/response.rs @@ -8,8 +8,9 @@ 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) +/// [Response type](http://fetch.spec.whatwg.org/#concept-response-type) #[deriving(Clone, PartialEq)] pub enum ResponseType { Basic, @@ -19,7 +20,7 @@ pub enum ResponseType { Opaque } -// [Response termination reason](http://fetch.spec.whatwg.org/#concept-response-termination-reason) +/// [Response termination reason](http://fetch.spec.whatwg.org/#concept-response-termination-reason) #[deriving(Clone)] pub enum TerminationReason { EndUserAbort, @@ -27,7 +28,30 @@ pub enum TerminationReason { Timeout } -// A [Response](http://fetch.spec.whatwg.org/#concept-response) as defined by the Fetch spec +/// 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), + Done(Vec), +} + +#[unstable = "I haven't yet decided exactly how the interface for this will be"] +pub enum ResponseMsg { + Chunk(Vec), + Finished, + Errored +} + +#[unstable = "I haven't yet decided exactly how the interface for this will be"] +pub struct ResponseLoader { + response: Response, + chan: Receiver +} + +/// A [Response](http://fetch.spec.whatwg.org/#concept-response) as defined by the Fetch spec #[deriving(Clone)] pub struct Response { pub response_type: ResponseType, @@ -35,7 +59,7 @@ pub struct Response { pub url: Option, pub status: Status, pub headers: HeaderCollection, - pub body: Option>, + 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>, } @@ -48,7 +72,19 @@ impl Response { url: None, status: StatusOk, headers: HeaderCollection::new(), - body: None, + 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 } } @@ -100,7 +136,7 @@ impl Response { Opaque => { response.headers = HeaderCollection::new(); response.status = UnregisteredStatus(0, "".to_string()); - response.body = None; + response.body = Empty; } } response From a3b5395d5069fabe24854778dd976d7b1bf03a58 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sat, 23 Aug 2014 12:14:25 +0530 Subject: [PATCH 2/4] Add a basic CORS Cache and a CORS Cache trait --- src/components/net/fetch/cors_cache.rs | 153 +++++++++++++++++++++++++ src/components/net/net.rs | 2 + 2 files changed, 155 insertions(+) create mode 100644 src/components/net/fetch/cors_cache.rs diff --git a/src/components/net/fetch/cors_cache.rs b/src/components/net/fetch/cors_cache.rs new file mode 100644 index 00000000000..482dc093e47 --- /dev/null +++ b/src/components/net/fetch/cors_cache.rs @@ -0,0 +1,153 @@ +/* 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 http::method::Method; +use std::ascii::StrAsciiExt; +use time; +use time::{now, Timespec}; +use url::Url; + +#[deriving(Clone)] +pub struct BasicCORSCache(Vec); + +/// 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 { + origin: Url, + destination: Url, +} + +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); + + /// [Finds an entry with a matching header](http://fetch.spec.whatwg.org/#concept-cache-match-header) + fn find_entry_by_header<'a>(&'a mut self, request: &CacheRequestDetails, header_name: &str) -> Option<&'a mut CORSCacheEntry>; + + /// Returns true if an entry with a matching header is found + fn match_header(&mut self, request: &CacheRequestDetails, header_name: &str) -> bool { + self.find_entry_by_header(request, header_name).is_some() + } + + /// Updates max age if an entry for the same header is found. + fn match_header_and_update(&mut self, request: &CacheRequestDetails, header_name: &str, new_max_age: uint) -> bool { + self.find_entry_by_header(request, header_name).map(|e| e.max_age = new_max_age).is_some() + } + + /// [Finds an entry with a matching method](http://fetch.spec.whatwg.org/#concept-cache-match-method) + fn find_entry_by_method<'a>(&'a mut self, request: &CacheRequestDetails, method: &Method) -> Option<&'a mut CORSCacheEntry>; + + /// Returns true if an entry with a matching method is found + fn match_method(&mut self, request: &CacheRequestDetails, method: &Method) -> bool { + self.find_entry_by_method(request, method).is_some() + } + + /// Updates max age if an entry for the same method is found. + fn match_method_and_update(&mut self, request: &CacheRequestDetails, method: &Method, new_max_age: uint) -> bool { + self.find_entry_by_method(request, method).map(|e| e.max_age = new_max_age).is_some() + } + + /// Insert an entry + fn insert(&mut self, entry: CORSCacheEntry); +} + +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 = 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 = buf.move_iter().filter(|e| now.sec > e.created.sec + e.max_age as i64).collect(); + *self = BasicCORSCache(new_buf); + } + + /// http://fetch.spec.whatwg.org/#concept-cache-match-header + 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; + // Credentials are not yet implemented here + 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.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; + // Credentials are not yet implemented here + 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.header_or_method.match_method(method)); + entry + } + + fn insert(&mut self, entry: CORSCacheEntry) { + self.cleanup(); + let BasicCORSCache(ref mut buf) = *self; + buf.push(entry); + } +} diff --git a/src/components/net/net.rs b/src/components/net/net.rs index 9e52519319b..94290bdd7ff 100644 --- a/src/components/net/net.rs +++ b/src/components/net/net.rs @@ -18,6 +18,7 @@ extern crate serialize; extern crate servo_util = "util"; extern crate stb_image; extern crate sync; +extern crate time; extern crate url; /// Image handling. @@ -42,4 +43,5 @@ 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; } From 5d7438a7dbeda64a3aa853d6ed27a76c2a26949a Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sat, 23 Aug 2014 14:48:10 +0530 Subject: [PATCH 3/4] Add a task-based CORS Cache --- src/components/net/fetch/cors_cache.rs | 249 ++++++++++++++++++++----- src/components/net/fetch/request.rs | 7 +- 2 files changed, 208 insertions(+), 48 deletions(-) diff --git a/src/components/net/fetch/cors_cache.rs b/src/components/net/fetch/cors_cache.rs index 482dc093e47..529edc683f7 100644 --- a/src/components/net/fetch/cors_cache.rs +++ b/src/components/net/fetch/cors_cache.rs @@ -4,14 +4,13 @@ use http::method::Method; use std::ascii::StrAsciiExt; +use std::comm::{Sender, Receiver, channel}; use time; use time::{now, Timespec}; use url::Url; -#[deriving(Clone)] -pub struct BasicCORSCache(Vec); - /// Union type for CORS cache entries +/// /// Each entry might pertain to a header or method #[deriving(Clone)] pub enum HeaderOrMethod { @@ -61,65 +60,44 @@ impl CORSCacheEntry { /// Properties of Request required to cache match. pub struct CacheRequestDetails { - origin: Url, - destination: Url, + pub origin: Url, + pub destination: Url, + pub credentials: bool } -trait CORSCache { +/// 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); + fn clear (&mut self, request: CacheRequestDetails); /// Remove old entries fn cleanup(&mut self); - /// [Finds an entry with a matching header](http://fetch.spec.whatwg.org/#concept-cache-match-header) - fn find_entry_by_header<'a>(&'a mut self, request: &CacheRequestDetails, header_name: &str) -> Option<&'a mut CORSCacheEntry>; + /// 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; - /// Returns true if an entry with a matching header is found - fn match_header(&mut self, request: &CacheRequestDetails, header_name: &str) -> bool { - self.find_entry_by_header(request, header_name).is_some() - } + /// 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; - /// Updates max age if an entry for the same header is found. - fn match_header_and_update(&mut self, request: &CacheRequestDetails, header_name: &str, new_max_age: uint) -> bool { - self.find_entry_by_header(request, header_name).map(|e| e.max_age = new_max_age).is_some() - } - - /// [Finds an entry with a matching method](http://fetch.spec.whatwg.org/#concept-cache-match-method) - fn find_entry_by_method<'a>(&'a mut self, request: &CacheRequestDetails, method: &Method) -> Option<&'a mut CORSCacheEntry>; - - /// Returns true if an entry with a matching method is found - fn match_method(&mut self, request: &CacheRequestDetails, method: &Method) -> bool { - self.find_entry_by_method(request, method).is_some() - } - - /// Updates max age if an entry for the same method is found. - fn match_method_and_update(&mut self, request: &CacheRequestDetails, method: &Method, new_max_age: uint) -> bool { - self.find_entry_by_method(request, method).map(|e| e.max_age = new_max_age).is_some() - } + /// 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); } -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 = buf.move_iter().filter(|e| e.origin == request.origin && request.destination == e.url).collect(); - *self = BasicCORSCache(new_buf); - } +/// A simple, vector-based CORS Cache +#[deriving(Clone)] +pub struct BasicCORSCache(Vec); - // Remove old entries - fn cleanup(&mut self) { - let BasicCORSCache(buf) = self.clone(); - let now = time::now().to_timespec(); - let new_buf: Vec = buf.move_iter().filter(|e| now.sec > e.created.sec + e.max_age as i64).collect(); - *self = BasicCORSCache(new_buf); - } - /// http://fetch.spec.whatwg.org/#concept-cache-match-header +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; @@ -128,6 +106,7 @@ impl CORSCache for BasicCORSCache { 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 } @@ -141,9 +120,58 @@ impl CORSCache for BasicCORSCache { 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 = 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 = 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).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.clone()))); + false + } + } + } fn insert(&mut self, entry: CORSCacheEntry) { self.cleanup(); @@ -151,3 +179,132 @@ impl CORSCache for BasicCORSCache { buf.push(entry); } } + +/// Various messages that can be sent to a CORSCacheTask +pub enum CORSCacheTaskMsg { + Clear(CacheRequestDetails, Sender<()>), + Cleanup(Sender<()>), + MatchHeader(CacheRequestDetails, String, Sender), + MatchHeaderUpdate(CacheRequestDetails, String, uint, Sender), + MatchMethod(CacheRequestDetails, Method, Sender), + MatchMethodUpdate(CacheRequestDetails, Method, uint, Sender), + Insert(CORSCacheEntry, Sender<()>) +} + +/// 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; + +impl CORSCache for CORSCacheSender { + fn clear (&mut self, request: CacheRequestDetails) { + let (tx, rx) = channel(); + self.send(Clear(request, tx)); + rx.recv_opt().ok(); + } + + fn cleanup(&mut self) { + let (tx, rx) = channel(); + self.send(Cleanup(tx)); + rx.recv_opt().ok(); + } + + 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().ok().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().ok().unwrap_or(false) + } + + fn match_method(&mut self, request: CacheRequestDetails, method: &Method) -> bool { + let (tx, rx) = channel(); + self.send(MatchMethod(request, method.clone(), tx)); + rx.recv_opt().ok().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.clone(), new_max_age, tx)); + rx.recv_opt().ok().unwrap_or(false) + } + + fn insert(&mut self, entry: CORSCacheEntry) { + let (tx, rx) = channel(); + self.send(Insert(entry, tx)); + rx.recv_opt().ok() ; + } +} + +/// 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, + pub 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 + pub fn run(&mut self) { + loop { + // The recv() here should never fail, we always + // carry a copy of the Sender with us. + 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(()); + } + } + } + } +} \ No newline at end of file diff --git a/src/components/net/fetch/request.rs b/src/components/net/fetch/request.rs index 2dfd5572a97..bd5d87b7950 100644 --- a/src/components/net/fetch/request.rs +++ b/src/components/net/fetch/request.rs @@ -5,6 +5,7 @@ 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) @@ -77,7 +78,8 @@ pub struct Request { pub use_url_credentials: bool, pub manual_redirect: bool, pub redirect_count: uint, - pub response_tainting: ResponseTainting + pub response_tainting: ResponseTainting, + pub cache: Option> } impl Request { @@ -103,7 +105,8 @@ impl Request { use_url_credentials: false, manual_redirect: false, redirect_count: 0, - response_tainting: Basic + response_tainting: Basic, + cache: None } } From d326ba03770e071b7f3535fff40dfeed85ca7c0d Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sat, 23 Aug 2014 21:35:29 +0530 Subject: [PATCH 4/4] Some docs --- src/components/net/fetch/cors_cache.rs | 70 ++++++++++++++------------ src/components/net/fetch/request.rs | 4 +- 2 files changed, 40 insertions(+), 34 deletions(-) diff --git a/src/components/net/fetch/cors_cache.rs b/src/components/net/fetch/cors_cache.rs index 529edc683f7..fb6676e8064 100644 --- a/src/components/net/fetch/cors_cache.rs +++ b/src/components/net/fetch/cors_cache.rs @@ -2,6 +2,13 @@ * 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 ``, `