aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2016-04-28 13:36:05 -0700
committerbors-servo <lbergstrom+bors@mozilla.com>2016-04-28 13:36:05 -0700
commit3d38a60cee8a2e19ae8f04df7c2374fc9d97999c (patch)
treed05a733f3366cf6b0a77b255f0e9ba71be132f9f /components
parent3836c2c4cba1f49ea5ce3ce802b0bd604213c2a2 (diff)
parent483f07c8f012ded73347dd0307eb4d09dba96a94 (diff)
downloadservo-3d38a60cee8a2e19ae8f04df7c2374fc9d97999c.tar.gz
servo-3d38a60cee8a2e19ae8f04df7c2374fc9d97999c.zip
Auto merge of #10867 - danlrobertson:sandbox, r=KiChjang
Fix logic for cors cache match The current logic for a cors cache match does not consider "credentials is false and request's credentials mode is not "include" or credentials is true." I could have missed something, but `CacheRequestDetails::credentials` is set to true if credentials mode is "include", and false otherwise. So `(!cors_cache.credentials && !cors_req.credentials) || cors_cache.credentials` would be directly following the spec, but unless I'm mistaken `cors_cache.credentials || !cors_req.credentials` is logically the same. Fixes: #10525 <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="35" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/10867) <!-- Reviewable:end -->
Diffstat (limited to 'components')
-rw-r--r--components/net/fetch/cors_cache.rs227
-rw-r--r--components/net/fetch/methods.rs43
-rw-r--r--components/net_traits/request.rs2
3 files changed, 60 insertions, 212 deletions
diff --git a/components/net/fetch/cors_cache.rs b/components/net/fetch/cors_cache.rs
index dc640ce4c37..1f6d39f71b7 100644
--- a/components/net/fetch/cors_cache.rs
+++ b/components/net/fetch/cors_cache.rs
@@ -12,7 +12,6 @@
use hyper::method::Method;
use net_traits::request::Origin;
use std::ascii::AsciiExt;
-use std::sync::mpsc::{Sender, Receiver, channel};
use time;
use time::{now, Timespec};
use url::Url;
@@ -20,7 +19,7 @@ use url::Url;
/// Union type for CORS cache entries
///
/// Each entry might pertain to a header or method
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub enum HeaderOrMethod {
HeaderData(String),
MethodData(Method)
@@ -43,7 +42,7 @@ impl HeaderOrMethod {
}
/// An entry in the CORS cache
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub struct CORSCacheEntry {
pub origin: Origin,
pub url: Url,
@@ -74,51 +73,20 @@ pub struct CacheRequestDetails {
pub credentials: bool
}
-/// Trait for a generic CORS Cache
-pub trait CORSCache {
- /// [Clear the cache](https://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](https://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](https://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: u32) -> bool;
-
- /// Returns true if an entry with a
- /// [matching method](https://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](https://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: u32) -> bool;
- /// Insert an entry
- fn insert(&mut self, entry: CORSCacheEntry);
-}
-
-/// A simple, vector-based CORS Cache
-#[derive(Clone)]
-pub struct BasicCORSCache(Vec<CORSCacheEntry>);
-
fn match_headers(cors_cache: &CORSCacheEntry, cors_req: &CacheRequestDetails) -> bool {
cors_cache.origin == cors_req.origin &&
cors_cache.url == cors_req.destination &&
- cors_cache.credentials == cors_req.credentials
+ (cors_cache.credentials || !cors_req.credentials)
}
-impl BasicCORSCache {
+/// A simple, vector-based CORS Cache
+#[derive(Clone)]
+pub struct CORSCache(Vec<CORSCacheEntry>);
+
+impl CORSCache {
- pub fn new() -> BasicCORSCache {
- BasicCORSCache(vec![])
+ pub fn new() -> CORSCache {
+ CORSCache(vec![])
}
fn find_entry_by_header<'a>(&'a mut self, request: &CacheRequestDetails,
@@ -133,33 +101,37 @@ impl BasicCORSCache {
self.cleanup();
self.0.iter_mut().find(|e| match_headers(e, request) && e.header_or_method.match_method(&method))
}
-}
-impl CORSCache for BasicCORSCache {
- /// https://fetch.spec.whatwg.org/#concept-cache-clear
- #[allow(dead_code)]
- fn clear (&mut self, request: CacheRequestDetails) {
- let BasicCORSCache(buf) = self.clone();
+ /// [Clear the cache](https://fetch.spec.whatwg.org/#concept-cache-clear)
+ pub fn clear (&mut self, request: CacheRequestDetails) {
+ let CORSCache(buf) = self.clone();
let new_buf: Vec<CORSCacheEntry> =
buf.into_iter().filter(|e| e.origin == request.origin && request.destination == e.url).collect();
- *self = BasicCORSCache(new_buf);
+ *self = CORSCache(new_buf);
}
- // Remove old entries
- fn cleanup(&mut self) {
- let BasicCORSCache(buf) = self.clone();
+ /// Remove old entries
+ pub fn cleanup(&mut self) {
+ let CORSCache(buf) = self.clone();
let now = time::now().to_timespec();
let new_buf: Vec<CORSCacheEntry> = buf.into_iter()
- .filter(|e| now.sec > e.created.sec + e.max_age as i64)
+ .filter(|e| now.sec < e.created.sec + e.max_age as i64)
.collect();
- *self = BasicCORSCache(new_buf);
+ *self = CORSCache(new_buf);
}
- fn match_header(&mut self, request: CacheRequestDetails, header_name: &str) -> bool {
+ /// Returns true if an entry with a
+ /// [matching header](https://fetch.spec.whatwg.org/#concept-cache-match-header) is found
+ pub 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: u32) -> bool {
+ /// Updates max age if an entry for a
+ /// [matching header](https://fetch.spec.whatwg.org/#concept-cache-match-header) is found.
+ ///
+ /// If not, it will insert an equivalent entry
+ pub fn match_header_and_update(&mut self, request: CacheRequestDetails,
+ header_name: &str, new_max_age: u32) -> bool {
match self.find_entry_by_header(&request, header_name).map(|e| e.max_age = new_max_age) {
Some(_) => true,
None => {
@@ -171,11 +143,17 @@ impl CORSCache for BasicCORSCache {
}
}
- fn match_method(&mut self, request: CacheRequestDetails, method: Method) -> bool {
+ /// Returns true if an entry with a
+ /// [matching method](https://fetch.spec.whatwg.org/#concept-cache-match-method) is found
+ pub 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: u32) -> bool {
+ /// Updates max age if an entry for
+ /// [a matching method](https://fetch.spec.whatwg.org/#concept-cache-match-method) is found.
+ ///
+ /// If not, it will insert an equivalent entry
+ pub fn match_method_and_update(&mut self, request: CacheRequestDetails, method: Method, new_max_age: u32) -> bool {
match self.find_entry_by_method(&request, method.clone()).map(|e| e.max_age = new_max_age) {
Some(_) => true,
None => {
@@ -186,138 +164,9 @@ impl CORSCache for BasicCORSCache {
}
}
- fn insert(&mut self, entry: CORSCacheEntry) {
+ /// Insert an entry
+ pub fn insert(&mut self, entry: CORSCacheEntry) {
self.cleanup();
self.0.push(entry);
}
}
-
-/// Various messages that can be sent to a CORSCacheThread
-pub enum CORSCacheThreadMsg {
- Clear(CacheRequestDetails, Sender<()>),
- Cleanup(Sender<()>),
- MatchHeader(CacheRequestDetails, String, Sender<bool>),
- MatchHeaderUpdate(CacheRequestDetails, String, u32, Sender<bool>),
- MatchMethod(CacheRequestDetails, Method, Sender<bool>),
- MatchMethodUpdate(CacheRequestDetails, Method, u32, Sender<bool>),
- Insert(CORSCacheEntry, Sender<()>),
- ExitMsg
-}
-
-/// A Sender to a CORSCacheThread
-///
-/// 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<CORSCacheThreadMsg>;
-
-impl CORSCache for CORSCacheSender {
- fn clear (&mut self, request: CacheRequestDetails) {
- let (tx, rx) = channel();
- let _ = self.send(CORSCacheThreadMsg::Clear(request, tx));
- let _ = rx.recv();
- }
-
- fn cleanup(&mut self) {
- let (tx, rx) = channel();
- let _ = self.send(CORSCacheThreadMsg::Cleanup(tx));
- let _ = rx.recv();
- }
-
- fn match_header(&mut self, request: CacheRequestDetails, header_name: &str) -> bool {
- let (tx, rx) = channel();
- let _ = self.send(CORSCacheThreadMsg::MatchHeader(request, header_name.to_owned(), tx));
- rx.recv().unwrap_or(false)
- }
-
- fn match_header_and_update(&mut self, request: CacheRequestDetails, header_name: &str, new_max_age: u32) -> bool {
- let (tx, rx) = channel();
- let _ = self.send(CORSCacheThreadMsg::MatchHeaderUpdate(request, header_name.to_owned(), new_max_age, tx));
- rx.recv().unwrap_or(false)
- }
-
- fn match_method(&mut self, request: CacheRequestDetails, method: Method) -> bool {
- let (tx, rx) = channel();
- let _ = self.send(CORSCacheThreadMsg::MatchMethod(request, method, tx));
- rx.recv().unwrap_or(false)
- }
-
- fn match_method_and_update(&mut self, request: CacheRequestDetails, method: Method, new_max_age: u32) -> bool {
- let (tx, rx) = channel();
- let _ = self.send(CORSCacheThreadMsg::MatchMethodUpdate(request, method, new_max_age, tx));
- rx.recv().unwrap_or(false)
- }
-
- fn insert(&mut self, entry: CORSCacheEntry) {
- let (tx, rx) = channel();
- let _ = self.send(CORSCacheThreadMsg::Insert(entry, tx));
- let _ = rx.recv();
- }
-}
-
-/// A simple thread-based CORS Cache that can be sent messages
-///
-/// #Example
-/// ```ignore
-/// let thread = CORSCacheThread::new();
-/// let builder = ThreadBuilder::new().named("XHRThread");
-/// let mut sender = thread.sender();
-/// builder.spawn(move || { thread.run() });
-/// sender.insert(CORSCacheEntry::new(/* parameters here */));
-/// ```
-pub struct CORSCacheThread {
- receiver: Receiver<CORSCacheThreadMsg>,
- cache: BasicCORSCache,
- sender: CORSCacheSender
-}
-
-impl CORSCacheThread {
- pub fn new() -> CORSCacheThread {
- let (tx, rx) = channel();
- CORSCacheThread {
- receiver: rx,
- cache: BasicCORSCache(vec![]),
- sender: tx
- }
- }
-
- /// Provides a sender to the cache thread
- pub fn sender(&self) -> CORSCacheSender {
- self.sender.clone()
- }
-
- /// Runs the cache thread
- /// This blocks the current thread, so it is advised
- /// to spawn a new thread for this
- /// Send ExitMsg to the associated Sender to exit
- pub fn run(&mut self) {
- loop {
- match self.receiver.recv().unwrap() {
- CORSCacheThreadMsg::Clear(request, tx) => {
- self.cache.clear(request);
- let _ = tx.send(());
- },
- CORSCacheThreadMsg::Cleanup(tx) => {
- self.cache.cleanup();
- let _ = tx.send(());
- },
- CORSCacheThreadMsg::MatchHeader(request, header, tx) => {
- let _ = tx.send(self.cache.match_header(request, &header));
- },
- CORSCacheThreadMsg::MatchHeaderUpdate(request, header, new_max_age, tx) => {
- let _ = tx.send(self.cache.match_header_and_update(request, &header, new_max_age));
- },
- CORSCacheThreadMsg::MatchMethod(request, method, tx) => {
- let _ = tx.send(self.cache.match_method(request, method));
- },
- CORSCacheThreadMsg::MatchMethodUpdate(request, method, new_max_age, tx) => {
- let _ = tx.send(self.cache.match_method_and_update(request, method, new_max_age));
- },
- CORSCacheThreadMsg::Insert(entry, tx) => {
- self.cache.insert(entry);
- let _ = tx.send(());
- },
- CORSCacheThreadMsg::ExitMsg => break
- }
- }
- }
-}
diff --git a/components/net/fetch/methods.rs b/components/net/fetch/methods.rs
index 479c9bc9951..868d284707f 100644
--- a/components/net/fetch/methods.rs
+++ b/components/net/fetch/methods.rs
@@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use data_loader::decode;
-use fetch::cors_cache::{BasicCORSCache, CORSCache, CacheRequestDetails};
+use fetch::cors_cache::{CORSCache, CacheRequestDetails};
use http_loader::{NetworkHttpRequestFactory, create_http_connector, obtain_response};
use hyper::header::{Accept, AcceptLanguage, Authorization, AccessControlAllowCredentials};
use hyper::header::{AccessControlAllowOrigin, AccessControlAllowHeaders, AccessControlAllowMethods};
@@ -40,6 +40,10 @@ pub fn fetch_async(request: Request, listener: Box<AsyncFetchListener + Send>) {
/// [Fetch](https://fetch.spec.whatwg.org#concept-fetch)
pub fn fetch(request: Rc<Request>) -> Response {
+ fetch_with_cors_cache(request, &mut CORSCache::new())
+}
+
+pub fn fetch_with_cors_cache(request: Rc<Request>, cache: &mut CORSCache) -> Response {
// Step 1
if request.window.get() == Window::Client {
@@ -102,11 +106,11 @@ pub fn fetch(request: Rc<Request>) -> Response {
// TODO: create a fetch record and append it to request's client's fetch group list
}
// Step 7
- main_fetch(request, false, false)
+ main_fetch(request, cache, false, false)
}
/// [Main fetch](https://fetch.spec.whatwg.org/#concept-main-fetch)
-fn main_fetch(request: Rc<Request>, cors_flag: bool, recursive_flag: bool) -> Response {
+fn main_fetch(request: Rc<Request>, cache: &mut CORSCache, cors_flag: bool, recursive_flag: bool) -> Response {
// TODO: Implement main fetch spec
// Step 1
@@ -156,14 +160,14 @@ fn main_fetch(request: Rc<Request>, cors_flag: bool, recursive_flag: bool) -> Re
current_url.scheme() == "about" ||
request.mode == RequestMode::Navigate {
- basic_fetch(request.clone())
+ basic_fetch(request.clone(), cache)
} else if request.mode == RequestMode::SameOrigin {
Response::network_error()
} else if request.mode == RequestMode::NoCORS {
request.response_tainting.set(ResponseTainting::Opaque);
- basic_fetch(request.clone())
+ basic_fetch(request.clone(), cache)
} else if !matches!(current_url.scheme(), "http" | "https") {
Response::network_error()
@@ -175,7 +179,7 @@ fn main_fetch(request: Rc<Request>, cors_flag: bool, recursive_flag: bool) -> Re
request.response_tainting.set(ResponseTainting::CORSTainting);
request.redirect_mode.set(RedirectMode::Error);
- let response = http_fetch(request.clone(), BasicCORSCache::new(), true, true, false);
+ let response = http_fetch(request.clone(), cache, true, true, false);
if response.is_network_error() {
// TODO clear cache entries using request
}
@@ -183,7 +187,7 @@ fn main_fetch(request: Rc<Request>, cors_flag: bool, recursive_flag: bool) -> Re
} else {
request.response_tainting.set(ResponseTainting::CORSTainting);
- http_fetch(request.clone(), BasicCORSCache::new(), true, false, false)
+ http_fetch(request.clone(), cache, true, false, false)
}
}
};
@@ -280,7 +284,7 @@ fn main_fetch(request: Rc<Request>, cors_flag: bool, recursive_flag: bool) -> Re
}
/// [Basic fetch](https://fetch.spec.whatwg.org#basic-fetch)
-fn basic_fetch(request: Rc<Request>) -> Response {
+fn basic_fetch(request: Rc<Request>, cache: &mut CORSCache) -> Response {
let url = request.current_url();
@@ -294,7 +298,7 @@ fn basic_fetch(request: Rc<Request>) -> Response {
},
"http" | "https" => {
- http_fetch(request.clone(), BasicCORSCache::new(), false, false, false)
+ http_fetch(request.clone(), cache, false, false, false)
},
"data" => {
@@ -324,7 +328,7 @@ fn basic_fetch(request: Rc<Request>) -> Response {
/// [HTTP fetch](https://fetch.spec.whatwg.org#http-fetch)
fn http_fetch(request: Rc<Request>,
- mut cache: BasicCORSCache,
+ cache: &mut CORSCache,
cors_flag: bool,
cors_preflight_flag: bool,
authentication_fetch_flag: bool) -> Response {
@@ -394,7 +398,7 @@ fn http_fetch(request: Rc<Request>,
// Sub-substep 1
if method_mismatch || header_mismatch {
- let preflight_result = cors_preflight_fetch(request.clone(), Some(cache));
+ let preflight_result = cors_preflight_fetch(request.clone(), cache);
// Sub-substep 2
if preflight_result.response_type == ResponseType::Error {
return Response::network_error();
@@ -443,7 +447,7 @@ fn http_fetch(request: Rc<Request>,
RedirectMode::Follow => {
// set back to default
response.return_internal.set(true);
- http_redirect_fetch(request, Rc::new(response), cors_flag)
+ http_redirect_fetch(request, cache, Rc::new(response), cors_flag)
}
}
},
@@ -466,7 +470,7 @@ fn http_fetch(request: Rc<Request>,
}
// Step 4
- return http_fetch(request, BasicCORSCache::new(), cors_flag, cors_preflight_flag, true);
+ return http_fetch(request, cache, cors_flag, cors_preflight_flag, true);
}
// Code 407
@@ -482,7 +486,7 @@ fn http_fetch(request: Rc<Request>,
// TODO: Prompt the user for proxy authentication credentials
// Step 4
- return http_fetch(request, BasicCORSCache::new(),
+ return http_fetch(request, cache,
cors_flag, cors_preflight_flag,
authentication_fetch_flag);
}
@@ -503,6 +507,7 @@ fn http_fetch(request: Rc<Request>,
/// [HTTP redirect fetch](https://fetch.spec.whatwg.org#http-redirect-fetch)
fn http_redirect_fetch(request: Rc<Request>,
+ cache: &mut CORSCache,
response: Rc<Response>,
cors_flag: bool) -> Response {
@@ -580,7 +585,7 @@ fn http_redirect_fetch(request: Rc<Request>,
request.url_list.borrow_mut().push(location_url);
// Step 15
- main_fetch(request, cors_flag, true)
+ main_fetch(request, cache, cors_flag, true)
}
/// [HTTP network or cache fetch](https://fetch.spec.whatwg.org#http-network-or-cache-fetch)
@@ -917,7 +922,7 @@ fn http_network_fetch(request: Rc<Request>,
}
/// [CORS preflight fetch](https://fetch.spec.whatwg.org#cors-preflight-fetch)
-fn cors_preflight_fetch(request: Rc<Request>, cache: Option<BasicCORSCache>) -> Response {
+fn cors_preflight_fetch(request: Rc<Request>, cache: &mut CORSCache) -> Response {
// Step 1
let mut preflight = Request::new(request.current_url(), Some(request.origin.borrow().clone()), false);
*preflight.method.borrow_mut() = Method::Options;
@@ -995,12 +1000,6 @@ fn cors_preflight_fetch(request: Rc<Request>, cache: Option<BasicCORSCache>) ->
// TODO: Substep 9 - Need to define what an imposed limit on max-age is
- // Substep 10
- let mut cache = match cache {
- Some(c) => c,
- None => return response
- };
-
// Substep 11, 12
for method in &methods {
cache.match_method_and_update(CacheRequestDetails {
diff --git a/components/net_traits/request.rs b/components/net_traits/request.rs
index e02529263c5..675a78fd788 100644
--- a/components/net_traits/request.rs
+++ b/components/net_traits/request.rs
@@ -33,7 +33,7 @@ pub enum Destination {
}
/// A request [origin](https://fetch.spec.whatwg.org/#concept-request-origin)
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, Debug)]
pub enum Origin {
Client,
Origin(UrlOrigin)