mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Review fixes
This commit is contained in:
parent
8b9479f8bf
commit
9deecd793c
11 changed files with 44 additions and 549 deletions
|
@ -312,6 +312,8 @@ fn main_fetch(request: Rc<Request>, cache: &mut CORSCache, cors_flag: bool,
|
|||
if let Some(ref mut target) = *target {
|
||||
target.process_response_chunk(vec.clone());
|
||||
}
|
||||
} else {
|
||||
assert!(*response.body.lock().unwrap() == ResponseBody::Empty)
|
||||
}
|
||||
|
||||
// overloaded similarly to process_response
|
||||
|
@ -357,6 +359,8 @@ fn main_fetch(request: Rc<Request>, cache: &mut CORSCache, cors_flag: bool,
|
|||
// obtained synchronously via basic_fetch for data/file/about/etc
|
||||
// We should still send the body across as a chunk
|
||||
target.process_response_chunk(vec.clone());
|
||||
} else {
|
||||
assert!(*response.body.lock().unwrap() == ResponseBody::Empty)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -820,8 +824,10 @@ fn http_network_or_cache_fetch(request: Rc<Request>,
|
|||
if !http_request.use_url_credentials || !has_credentials(¤t_url) {
|
||||
authorization_value = Some(basic);
|
||||
}
|
||||
} else if authentication_fetch_flag {
|
||||
// Substep 5
|
||||
}
|
||||
|
||||
// Substep 5
|
||||
if authentication_fetch_flag && authorization_value.is_none() {
|
||||
if has_credentials(¤t_url) {
|
||||
authorization_value = Some(Basic {
|
||||
username: current_url.username().to_owned(),
|
||||
|
|
|
@ -435,9 +435,9 @@ fn strip_url(mut referrer_url: Url, origin_only: bool) -> Option<Url> {
|
|||
|
||||
/// https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer
|
||||
pub fn determine_request_referrer(headers: &mut Headers,
|
||||
referrer_policy: Option<ReferrerPolicy>,
|
||||
referrer_url: Option<Url>,
|
||||
url: Url) -> Option<Url> {
|
||||
referrer_policy: Option<ReferrerPolicy>,
|
||||
referrer_url: Option<Url>,
|
||||
url: Url) -> Option<Url> {
|
||||
//TODO - algorithm step 2 not addressed
|
||||
assert!(!headers.has::<Referer>());
|
||||
if let Some(ref_url) = referrer_url {
|
||||
|
|
|
@ -117,7 +117,7 @@ pub struct RequestInit {
|
|||
pub unsafe_request: bool,
|
||||
pub same_origin_data: bool,
|
||||
pub body: Option<Vec<u8>>,
|
||||
// TODO: cleint object
|
||||
// TODO: client object
|
||||
pub destination: Destination,
|
||||
pub synchronous: bool,
|
||||
pub mode: RequestMode,
|
||||
|
@ -214,7 +214,9 @@ impl Request {
|
|||
}
|
||||
|
||||
pub fn from_init(init: RequestInit) -> Request {
|
||||
let mut req = Request::new(init.url, None, false);
|
||||
let mut req = Request::new(init.url,
|
||||
Some(Origin::Origin(init.origin.origin())),
|
||||
false);
|
||||
*req.method.borrow_mut() = init.method;
|
||||
*req.headers.borrow_mut() = init.headers;
|
||||
req.unsafe_request = init.unsafe_request;
|
||||
|
@ -226,7 +228,6 @@ impl Request {
|
|||
req.use_cors_preflight = init.use_cors_preflight;
|
||||
req.credentials_mode = init.credentials_mode;
|
||||
req.use_url_credentials = init.use_url_credentials;
|
||||
*req.origin.borrow_mut() = Origin::Origin(init.origin.origin());
|
||||
*req.referer.borrow_mut() = if let Some(url) = init.referer_url {
|
||||
Referer::RefererUrl(url)
|
||||
} else {
|
||||
|
|
|
@ -226,9 +226,13 @@ impl Response {
|
|||
let mut metadata = if let Some(ref url) = self.url {
|
||||
Metadata::default(url.clone())
|
||||
} else {
|
||||
return Err(NetworkError::Internal("No url found".to_string()));
|
||||
return Err(NetworkError::Internal("No url found in response".to_string()));
|
||||
};
|
||||
|
||||
if self.is_network_error() {
|
||||
return Err(NetworkError::Internal("Cannot extract metadata from network error".to_string()));
|
||||
}
|
||||
|
||||
metadata.set_content_type(match self.headers.get() {
|
||||
Some(&ContentType(ref mime)) => Some(mime),
|
||||
None => None
|
||||
|
|
|
@ -60,7 +60,6 @@ smallvec = "0.1"
|
|||
string_cache = {version = "0.2.18", features = ["heap_size", "unstable"]}
|
||||
style = {path = "../style"}
|
||||
time = "0.1.12"
|
||||
unicase = "1.0"
|
||||
url = {version = "1.0.0", features = ["heap_size", "query_encoding"]}
|
||||
util = {path = "../util"}
|
||||
uuid = {version = "0.2", features = ["v4"]}
|
||||
|
|
|
@ -1,490 +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 partial implementation of CORS
|
||||
//! 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 hyper::client::Request;
|
||||
use hyper::header::{AccessControlAllowHeaders, AccessControlRequestHeaders};
|
||||
use hyper::header::{AccessControlAllowMethods, AccessControlRequestMethod};
|
||||
use hyper::header::{AccessControlAllowOrigin, AccessControlMaxAge};
|
||||
use hyper::header::{ContentType, Host};
|
||||
use hyper::header::{HeaderView, Headers};
|
||||
use hyper::method::Method;
|
||||
use hyper::mime::{Mime, SubLevel, TopLevel};
|
||||
use hyper::status::StatusClass::Success;
|
||||
use net_traits::{AsyncResponseListener, Metadata, NetworkError, ResponseAction};
|
||||
use network_listener::{NetworkListener, PreInvoke};
|
||||
use script_runtime::ScriptChan;
|
||||
use std::ascii::AsciiExt;
|
||||
use std::borrow::ToOwned;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use time::{self, Timespec, now};
|
||||
use unicase::UniCase;
|
||||
use url::Url;
|
||||
use util::thread::spawn_named;
|
||||
|
||||
/// Interface for network listeners concerned with CORS checks. Proper network requests
|
||||
/// should be initiated from this method, based on the response provided.
|
||||
pub trait AsyncCORSResponseListener {
|
||||
fn response_available(&self, response: CORSResponse);
|
||||
}
|
||||
|
||||
#[derive(Clone, HeapSizeOf)]
|
||||
pub struct CORSRequest {
|
||||
pub origin: Url,
|
||||
pub destination: Url,
|
||||
pub mode: RequestMode,
|
||||
#[ignore_heap_size_of = "Defined in hyper"]
|
||||
pub method: Method,
|
||||
#[ignore_heap_size_of = "Defined in hyper"]
|
||||
pub headers: Headers,
|
||||
/// CORS preflight flag (https://fetch.spec.whatwg.org/#concept-http-fetch)
|
||||
/// Indicates that a CORS preflight request and/or cache check is to be performed
|
||||
pub preflight_flag: bool,
|
||||
}
|
||||
|
||||
/// https://fetch.spec.whatwg.org/#concept-request-mode
|
||||
/// This only covers some of the request modes. The
|
||||
/// `same-origin` and `no CORS` modes are unnecessary for XHR.
|
||||
#[derive(PartialEq, Copy, Clone, HeapSizeOf)]
|
||||
pub enum RequestMode {
|
||||
CORS, // CORS
|
||||
ForcedPreflight, // CORS-with-forced-preflight
|
||||
}
|
||||
|
||||
impl CORSRequest {
|
||||
/// Creates a CORS request if necessary. Will return an error when fetching is forbidden
|
||||
pub fn maybe_new(referer: Url,
|
||||
destination: Url,
|
||||
mode: RequestMode,
|
||||
method: Method,
|
||||
headers: Headers,
|
||||
same_origin_data_url_flag: bool)
|
||||
-> Result<Option<CORSRequest>, ()> {
|
||||
if referer.origin() == destination.origin() {
|
||||
return Ok(None); // Not cross-origin, proceed with a normal fetch
|
||||
}
|
||||
match destination.scheme() {
|
||||
// As per (https://fetch.spec.whatwg.org/#main-fetch 5.1.9), about URLs can be fetched
|
||||
// the same as a basic request.
|
||||
"about" if destination.path() == "blank" => Ok(None),
|
||||
// As per (https://fetch.spec.whatwg.org/#main-fetch 5.1.9), data URLs can be fetched
|
||||
// the same as a basic request if the request's method is GET and the
|
||||
// same-origin data-URL flag is set.
|
||||
"data" if same_origin_data_url_flag && method == Method::Get => Ok(None),
|
||||
"http" | "https" => {
|
||||
let mut req = CORSRequest::new(referer, destination, mode, method, headers);
|
||||
req.preflight_flag = !is_simple_method(&req.method) ||
|
||||
mode == RequestMode::ForcedPreflight;
|
||||
if req.headers.iter().any(|h| !is_simple_header(&h)) {
|
||||
req.preflight_flag = true;
|
||||
}
|
||||
Ok(Some(req))
|
||||
},
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
fn new(mut referer: Url,
|
||||
destination: Url,
|
||||
mode: RequestMode,
|
||||
method: Method,
|
||||
headers: Headers)
|
||||
-> CORSRequest {
|
||||
referer.set_fragment(None);
|
||||
referer.set_query(None);
|
||||
referer.set_path("");
|
||||
CORSRequest {
|
||||
origin: referer,
|
||||
destination: destination,
|
||||
mode: mode,
|
||||
method: method,
|
||||
headers: headers,
|
||||
preflight_flag: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn http_fetch_async(&self,
|
||||
listener: Box<AsyncCORSResponseListener + Send>,
|
||||
script_chan: Box<ScriptChan + Send>) {
|
||||
struct CORSContext {
|
||||
listener: Box<AsyncCORSResponseListener + Send>,
|
||||
response: Option<CORSResponse>,
|
||||
}
|
||||
|
||||
// This is shoe-horning the CORSReponse stuff into the rest of the async network
|
||||
// framework right now. It would be worth redesigning http_fetch to do this properly.
|
||||
impl AsyncResponseListener for CORSContext {
|
||||
fn headers_available(&mut self, _metadata: Result<Metadata, NetworkError>) {
|
||||
}
|
||||
|
||||
fn data_available(&mut self, _payload: Vec<u8>) {
|
||||
}
|
||||
|
||||
fn response_complete(&mut self, _status: Result<(), NetworkError>) {
|
||||
let response = self.response.take().unwrap();
|
||||
self.listener.response_available(response);
|
||||
}
|
||||
}
|
||||
impl PreInvoke for CORSContext {}
|
||||
|
||||
let context = CORSContext {
|
||||
listener: listener,
|
||||
response: None,
|
||||
};
|
||||
let listener = NetworkListener {
|
||||
context: Arc::new(Mutex::new(context)),
|
||||
script_chan: script_chan,
|
||||
};
|
||||
|
||||
// TODO: this exists only to make preflight check non-blocking
|
||||
// perhaps should be handled by the resource thread?
|
||||
let req = self.clone();
|
||||
spawn_named("cors".to_owned(), move || {
|
||||
let response = req.http_fetch();
|
||||
let mut context = listener.context.lock();
|
||||
let context = context.as_mut().unwrap();
|
||||
context.response = Some(response);
|
||||
listener.notify(ResponseAction::ResponseComplete(Ok(())));
|
||||
});
|
||||
}
|
||||
|
||||
/// http://fetch.spec.whatwg.org/#concept-http-fetch
|
||||
/// This method assumes that the CORS flag is set
|
||||
/// This does not perform the full HTTP fetch, rather it handles part of the CORS filtering
|
||||
/// if self.mode is ForcedPreflight, then the CORS-with-forced-preflight
|
||||
/// fetch flag is set as well
|
||||
pub fn http_fetch(&self) -> CORSResponse {
|
||||
let response = CORSResponse::new();
|
||||
// Step 2: Handle service workers (unimplemented)
|
||||
// Step 3
|
||||
// Substep 1: Service workers (unimplemented )
|
||||
// Substep 2
|
||||
let cache = &mut CORSCache(vec!()); // XXXManishearth Should come from user agent
|
||||
if self.preflight_flag &&
|
||||
!cache.match_method(self, &self.method) &&
|
||||
!self.headers.iter().all(|h| is_simple_header(&h) && cache.match_header(self, h.name())) &&
|
||||
(!is_simple_method(&self.method) || self.mode == RequestMode::ForcedPreflight) {
|
||||
return self.preflight_fetch();
|
||||
// Everything after this is part of XHR::fetch()
|
||||
// Expect the organization of code to improve once we have a fetch crate
|
||||
}
|
||||
response
|
||||
}
|
||||
|
||||
/// https://fetch.spec.whatwg.org/#cors-preflight-fetch
|
||||
fn preflight_fetch(&self) -> CORSResponse {
|
||||
let error = CORSResponse::new_error();
|
||||
let mut cors_response = CORSResponse::new();
|
||||
|
||||
// Step 1
|
||||
let mut preflight = self.clone();
|
||||
preflight.method = Method::Options;
|
||||
preflight.headers = Headers::new();
|
||||
// Step 2
|
||||
preflight.headers.set(AccessControlRequestMethod(self.method.clone()));
|
||||
|
||||
// Steps 3-5
|
||||
let mut header_names = vec![];
|
||||
for header in self.headers.iter() {
|
||||
header_names.push(header.name().to_owned());
|
||||
}
|
||||
header_names.sort();
|
||||
preflight.headers
|
||||
.set(AccessControlRequestHeaders(header_names.into_iter().map(UniCase).collect()));
|
||||
|
||||
let preflight_request = Request::new(preflight.method, preflight.destination);
|
||||
let mut req = match preflight_request {
|
||||
Ok(req) => req,
|
||||
Err(_) => return error,
|
||||
};
|
||||
|
||||
let host = req.headers().get::<Host>().unwrap().clone();
|
||||
*req.headers_mut() = preflight.headers.clone();
|
||||
req.headers_mut().set(host);
|
||||
let stream = match req.start() {
|
||||
Ok(s) => s,
|
||||
Err(_) => return error,
|
||||
};
|
||||
// Step 6
|
||||
let response = match stream.send() {
|
||||
Ok(r) => r,
|
||||
Err(_) => return error,
|
||||
};
|
||||
|
||||
// Step 7: We don't perform a CORS check here
|
||||
// FYI, fn allow_cross_origin_request() performs the CORS check
|
||||
match response.status.class() {
|
||||
Success => {}
|
||||
_ => return error,
|
||||
}
|
||||
cors_response.headers = response.headers.clone();
|
||||
// Substeps 1-3 (parsing rules: https://fetch.spec.whatwg.org/#http-new-header-syntax)
|
||||
let methods_substep4 = [self.method.clone()];
|
||||
let mut methods = match response.headers.get() {
|
||||
Some(&AccessControlAllowMethods(ref v)) => &**v,
|
||||
_ => return error,
|
||||
};
|
||||
let headers = match response.headers.get() {
|
||||
Some(&AccessControlAllowHeaders(ref h)) => h,
|
||||
_ => return error,
|
||||
};
|
||||
// Substep 4
|
||||
if methods.is_empty() && preflight.mode == RequestMode::ForcedPreflight {
|
||||
methods = &methods_substep4;
|
||||
}
|
||||
// Substep 5
|
||||
if !is_simple_method(&self.method) && !methods.iter().any(|m| m == &self.method) {
|
||||
return error;
|
||||
}
|
||||
// Substep 6
|
||||
for h in self.headers.iter() {
|
||||
if is_simple_header(&h) {
|
||||
continue;
|
||||
}
|
||||
if !headers.iter().any(|ref h2| h.name().eq_ignore_ascii_case(h2)) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
// Substeps 7-8
|
||||
let max_age = match response.headers.get() {
|
||||
Some(&AccessControlMaxAge(num)) => num,
|
||||
None => 0,
|
||||
};
|
||||
// Substep 9: Impose restrictions on max-age, if any (unimplemented)
|
||||
// Substeps 10-12: Add a cache (partially implemented, XXXManishearth)
|
||||
// This cache should come from the user agent, creating a new one here to check
|
||||
// for compile time errors
|
||||
let cache = &mut CORSCache(vec![]);
|
||||
for m in methods {
|
||||
let cache_match = cache.match_method_and_update(self, m, max_age);
|
||||
if !cache_match {
|
||||
cache.insert(CORSCacheEntry::new(self.origin.clone(),
|
||||
self.destination.clone(),
|
||||
max_age,
|
||||
false,
|
||||
HeaderOrMethod::MethodData(m.clone())));
|
||||
}
|
||||
}
|
||||
// Substeps 13-14
|
||||
for h in response.headers.iter() {
|
||||
let cache_match = cache.match_header_and_update(self, h.name(), max_age);
|
||||
if !cache_match {
|
||||
cache.insert(CORSCacheEntry::new(self.origin.clone(),
|
||||
self.destination.clone(),
|
||||
max_age,
|
||||
false,
|
||||
HeaderOrMethod::HeaderData(h.to_string())));
|
||||
}
|
||||
}
|
||||
// Substep 15
|
||||
cors_response
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct CORSResponse {
|
||||
pub network_error: bool,
|
||||
pub headers: Headers,
|
||||
}
|
||||
|
||||
impl CORSResponse {
|
||||
fn new() -> CORSResponse {
|
||||
CORSResponse {
|
||||
network_error: false,
|
||||
headers: Headers::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn new_error() -> CORSResponse {
|
||||
CORSResponse {
|
||||
network_error: true,
|
||||
headers: Headers::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CORS Cache stuff
|
||||
|
||||
/// A CORS cache object. Anchor it somewhere to the user agent.
|
||||
#[derive(Clone)]
|
||||
pub struct CORSCache(Vec<CORSCacheEntry>);
|
||||
|
||||
/// Union type for CORS cache entries
|
||||
/// Each entry might pertain to a header or method
|
||||
#[derive(Clone)]
|
||||
pub enum HeaderOrMethod {
|
||||
HeaderData(String),
|
||||
MethodData(Method),
|
||||
}
|
||||
|
||||
impl HeaderOrMethod {
|
||||
fn match_header(&self, header_name: &str) -> bool {
|
||||
match *self {
|
||||
HeaderOrMethod::HeaderData(ref s) => (&**s).eq_ignore_ascii_case(header_name),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn match_method(&self, method: &Method) -> bool {
|
||||
match *self {
|
||||
HeaderOrMethod::MethodData(ref m) => m == method,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// An entry in the CORS cache
|
||||
#[derive(Clone)]
|
||||
pub struct CORSCacheEntry {
|
||||
pub origin: Url,
|
||||
pub url: Url,
|
||||
pub max_age: u32,
|
||||
pub credentials: bool,
|
||||
pub header_or_method: HeaderOrMethod,
|
||||
created: Timespec,
|
||||
}
|
||||
|
||||
impl CORSCacheEntry {
|
||||
fn new(origin: Url,
|
||||
url: Url,
|
||||
max_age: u32,
|
||||
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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CORSCache {
|
||||
/// https://fetch.spec.whatwg.org/#concept-cache-clear
|
||||
#[allow(dead_code)]
|
||||
fn clear(&mut self, request: &CORSRequest) {
|
||||
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 = CORSCache(new_buf);
|
||||
}
|
||||
|
||||
// Remove old entries
|
||||
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)
|
||||
.collect();
|
||||
*self = CORSCache(new_buf);
|
||||
}
|
||||
|
||||
/// https://fetch.spec.whatwg.org/#concept-cache-match-header
|
||||
fn find_entry_by_header<'a>(&'a mut self,
|
||||
request: &CORSRequest,
|
||||
header_name: &str)
|
||||
-> Option<&'a mut CORSCacheEntry> {
|
||||
self.cleanup();
|
||||
// Credentials are not yet implemented here
|
||||
self.0.iter_mut().find(|e| {
|
||||
e.origin.scheme() == request.origin.scheme() &&
|
||||
e.origin.host_str() == request.origin.host_str() &&
|
||||
e.origin.port() == request.origin.port() &&
|
||||
e.url == request.destination &&
|
||||
e.header_or_method.match_header(header_name)
|
||||
})
|
||||
}
|
||||
|
||||
fn match_header(&mut self, request: &CORSRequest, header_name: &str) -> bool {
|
||||
self.find_entry_by_header(request, header_name).is_some()
|
||||
}
|
||||
|
||||
fn match_header_and_update(&mut self,
|
||||
request: &CORSRequest,
|
||||
header_name: &str,
|
||||
new_max_age: u32)
|
||||
-> bool {
|
||||
self.find_entry_by_header(request, header_name).map(|e| e.max_age = new_max_age).is_some()
|
||||
}
|
||||
|
||||
fn find_entry_by_method<'a>(&'a mut self,
|
||||
request: &CORSRequest,
|
||||
method: &Method)
|
||||
-> Option<&'a mut CORSCacheEntry> {
|
||||
// we can take the method from CORSRequest itself
|
||||
self.cleanup();
|
||||
// Credentials are not yet implemented here
|
||||
self.0.iter_mut().find(|e| {
|
||||
e.origin.scheme() == request.origin.scheme() &&
|
||||
e.origin.host_str() == request.origin.host_str() &&
|
||||
e.origin.port() == request.origin.port() &&
|
||||
e.url == request.destination &&
|
||||
e.header_or_method.match_method(method)
|
||||
})
|
||||
}
|
||||
|
||||
/// https://fetch.spec.whatwg.org/#concept-cache-match-method
|
||||
fn match_method(&mut self, request: &CORSRequest, method: &Method) -> bool {
|
||||
self.find_entry_by_method(request, method).is_some()
|
||||
}
|
||||
|
||||
fn match_method_and_update(&mut self,
|
||||
request: &CORSRequest,
|
||||
method: &Method,
|
||||
new_max_age: u32)
|
||||
-> bool {
|
||||
self.find_entry_by_method(request, method).map(|e| e.max_age = new_max_age).is_some()
|
||||
}
|
||||
|
||||
fn insert(&mut self, entry: CORSCacheEntry) {
|
||||
self.cleanup();
|
||||
self.0.push(entry);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_simple_header(h: &HeaderView) -> bool {
|
||||
// FIXME: use h.is::<HeaderType>() when AcceptLanguage and
|
||||
// ContentLanguage headers exist
|
||||
match &*h.name().to_ascii_lowercase() {
|
||||
"accept" | "accept-language" | "content-language" => true,
|
||||
"content-type" => match h.value() {
|
||||
Some(&ContentType(Mime(TopLevel::Text, SubLevel::Plain, _))) |
|
||||
Some(&ContentType(Mime(TopLevel::Application, SubLevel::WwwFormUrlEncoded, _))) |
|
||||
Some(&ContentType(Mime(TopLevel::Multipart, SubLevel::FormData, _))) => true,
|
||||
|
||||
_ => false,
|
||||
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_simple_method(m: &Method) -> bool {
|
||||
match *m {
|
||||
Method::Get | Method::Head | Method::Post => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Perform a CORS check on a header list and CORS request
|
||||
/// https://fetch.spec.whatwg.org/#cors-check
|
||||
pub fn allow_cross_origin_request(req: &CORSRequest, headers: &Headers) -> bool {
|
||||
match headers.get::<AccessControlAllowOrigin>() {
|
||||
Some(&AccessControlAllowOrigin::Any) => true, // Not always true, depends on credentials mode
|
||||
Some(&AccessControlAllowOrigin::Value(ref url)) => req.origin.as_str() == *url,
|
||||
Some(&AccessControlAllowOrigin::Null) |
|
||||
None => false,
|
||||
}
|
||||
}
|
|
@ -236,16 +236,15 @@ impl XMLHttpRequest {
|
|||
self.xhr.root().process_data_available(self.gen_id, self.buf.borrow().clone());
|
||||
}
|
||||
fn process_response_eof(&mut self, response: Result<(), NetworkError>) {
|
||||
match response {
|
||||
let rv = match response {
|
||||
Ok(()) => {
|
||||
let rv = self.xhr.root().process_response_complete(self.gen_id, Ok(()));
|
||||
*self.sync_status.borrow_mut() = Some(rv);
|
||||
self.xhr.root().process_response_complete(self.gen_id, Ok(()))
|
||||
}
|
||||
Err(e) => {
|
||||
let rv = self.xhr.root().process_response_complete(self.gen_id, Err(e));
|
||||
*self.sync_status.borrow_mut() = Some(rv);
|
||||
self.xhr.root().process_response_complete(self.gen_id, Err(e))
|
||||
}
|
||||
}
|
||||
};
|
||||
*self.sync_status.borrow_mut() = Some(rv);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -569,7 +568,7 @@ impl XMLHttpRequestMethods for XMLHttpRequest {
|
|||
CredentialsMode::CredentialsSameOrigin
|
||||
};
|
||||
let use_url_credentials = if let Some(ref url) = *self.request_url.borrow() {
|
||||
url.username().len() != 0 || url.password().is_some()
|
||||
!url.username().is_empty() || url.password().is_some()
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
|
@ -888,8 +887,6 @@ impl XMLHttpRequest {
|
|||
},
|
||||
};
|
||||
|
||||
// todo allow cors in mozbrowser
|
||||
|
||||
*self.response_url.borrow_mut() = metadata.final_url[..Position::AfterQuery].to_owned();
|
||||
|
||||
// XXXManishearth Clear cache entries in case of a network error
|
||||
|
|
|
@ -79,7 +79,6 @@ extern crate style;
|
|||
extern crate time;
|
||||
#[cfg(any(target_os = "macos", target_os = "linux"))]
|
||||
extern crate tinyfiledialogs;
|
||||
extern crate unicase;
|
||||
extern crate url;
|
||||
#[macro_use]
|
||||
extern crate util;
|
||||
|
@ -91,7 +90,6 @@ extern crate xml5ever;
|
|||
mod blob_url_store;
|
||||
pub mod bluetooth_blacklist;
|
||||
pub mod clipboard_provider;
|
||||
pub mod cors;
|
||||
mod devtools;
|
||||
pub mod document_loader;
|
||||
#[macro_use]
|
||||
|
|
1
components/servo/Cargo.lock
generated
1
components/servo/Cargo.lock
generated
|
@ -1916,7 +1916,6 @@ dependencies = [
|
|||
"style 0.0.1",
|
||||
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tinyfiledialogs 0.1.0 (git+https://github.com/jdm/tinyfiledialogs)",
|
||||
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"util 0.0.1",
|
||||
"uuid 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
1
ports/cef/Cargo.lock
generated
1
ports/cef/Cargo.lock
generated
|
@ -1774,7 +1774,6 @@ dependencies = [
|
|||
"style 0.0.1",
|
||||
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tinyfiledialogs 0.1.0 (git+https://github.com/jdm/tinyfiledialogs)",
|
||||
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"util 0.0.1",
|
||||
"uuid 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
|
@ -60,6 +60,10 @@ fn fetch_async(request: Request, target: Box<FetchTaskTarget + Send>) {
|
|||
});
|
||||
}
|
||||
|
||||
fn fetch_sync(request: Request) -> Response {
|
||||
fetch(Rc::new(request), &mut None, new_fetch_context())
|
||||
}
|
||||
|
||||
fn make_server<H: Handler + 'static>(handler: H) -> (Listening, Url) {
|
||||
// this is a Listening server because of handle_threads()
|
||||
let server = Server::http("0.0.0.0:0").unwrap().handle_threads(handler, 1).unwrap();
|
||||
|
@ -81,9 +85,7 @@ fn test_fetch_response_is_not_network_error() {
|
|||
let origin = Origin::Origin(url.origin());
|
||||
let mut request = Request::new(url, Some(origin), false);
|
||||
*request.referer.borrow_mut() = Referer::NoReferer;
|
||||
let wrapped_request = Rc::new(request);
|
||||
|
||||
let fetch_response = fetch(wrapped_request, &mut None, new_fetch_context());
|
||||
let fetch_response = fetch_sync(request);
|
||||
let _ = server.close();
|
||||
|
||||
if fetch_response.is_network_error() {
|
||||
|
@ -102,9 +104,7 @@ fn test_fetch_response_body_matches_const_message() {
|
|||
let origin = Origin::Origin(url.origin());
|
||||
let mut request = Request::new(url, Some(origin), false);
|
||||
*request.referer.borrow_mut() = Referer::NoReferer;
|
||||
let wrapped_request = Rc::new(request);
|
||||
|
||||
let fetch_response = fetch(wrapped_request, &mut None, new_fetch_context());
|
||||
let fetch_response = fetch_sync(request);
|
||||
let _ = server.close();
|
||||
|
||||
assert!(!fetch_response.is_network_error());
|
||||
|
@ -124,9 +124,7 @@ fn test_fetch_aboutblank() {
|
|||
let origin = Origin::Origin(url.origin());
|
||||
let mut request = Request::new(url, Some(origin), false);
|
||||
*request.referer.borrow_mut() = Referer::NoReferer;
|
||||
let wrapped_request = Rc::new(request);
|
||||
|
||||
let fetch_response = fetch(wrapped_request, &mut None, new_fetch_context());
|
||||
let fetch_response = fetch_sync(request);
|
||||
assert!(!fetch_response.is_network_error());
|
||||
assert!(*fetch_response.body.lock().unwrap() == ResponseBody::Done(vec![]));
|
||||
}
|
||||
|
@ -138,7 +136,7 @@ fn test_fetch_data() {
|
|||
let request = Request::new(url, Some(origin), false);
|
||||
request.same_origin_data.set(true);
|
||||
let expected_resp_body = "<p>Servo</p>".to_owned();
|
||||
let fetch_response = fetch(Rc::new(request), &mut None, new_fetch_context());
|
||||
let fetch_response = fetch_sync(request);
|
||||
|
||||
assert!(!fetch_response.is_network_error());
|
||||
assert_eq!(fetch_response.headers.len(), 1);
|
||||
|
@ -167,7 +165,7 @@ fn test_fetch_file() {
|
|||
let request = Request::new(url, Some(origin), false);
|
||||
request.same_origin_data.set(true);
|
||||
|
||||
let fetch_response = fetch(Rc::new(request), &mut None, new_fetch_context());
|
||||
let fetch_response = fetch_sync(request);
|
||||
assert!(!fetch_response.is_network_error());
|
||||
assert_eq!(fetch_response.headers.len(), 1);
|
||||
let content_type: &ContentType = fetch_response.headers.get().unwrap();
|
||||
|
@ -209,9 +207,7 @@ fn test_cors_preflight_fetch() {
|
|||
*request.referer.borrow_mut() = Referer::NoReferer;
|
||||
request.use_cors_preflight = true;
|
||||
request.mode = RequestMode::CORSMode;
|
||||
let wrapped_request = Rc::new(request);
|
||||
|
||||
let fetch_response = fetch(wrapped_request, &mut None, new_fetch_context());
|
||||
let fetch_response = fetch_sync(request);
|
||||
let _ = server.close();
|
||||
|
||||
assert!(!fetch_response.is_network_error());
|
||||
|
@ -298,9 +294,7 @@ fn test_cors_preflight_fetch_network_error() {
|
|||
*request.referer.borrow_mut() = Referer::NoReferer;
|
||||
request.use_cors_preflight = true;
|
||||
request.mode = RequestMode::CORSMode;
|
||||
let wrapped_request = Rc::new(request);
|
||||
|
||||
let fetch_response = fetch(wrapped_request, &mut None, new_fetch_context());
|
||||
let fetch_response = fetch_sync(request);
|
||||
let _ = server.close();
|
||||
|
||||
assert!(fetch_response.is_network_error());
|
||||
|
@ -321,9 +315,7 @@ fn test_fetch_response_is_basic_filtered() {
|
|||
let origin = Origin::Origin(url.origin());
|
||||
let mut request = Request::new(url, Some(origin), false);
|
||||
*request.referer.borrow_mut() = Referer::NoReferer;
|
||||
let wrapped_request = Rc::new(request);
|
||||
|
||||
let fetch_response = fetch(wrapped_request, &mut None, new_fetch_context());
|
||||
let fetch_response = fetch_sync(request);
|
||||
let _ = server.close();
|
||||
|
||||
assert!(!fetch_response.is_network_error());
|
||||
|
@ -369,9 +361,7 @@ fn test_fetch_response_is_cors_filtered() {
|
|||
let mut request = Request::new(url, Some(origin), false);
|
||||
*request.referer.borrow_mut() = Referer::NoReferer;
|
||||
request.mode = RequestMode::CORSMode;
|
||||
let wrapped_request = Rc::new(request);
|
||||
|
||||
let fetch_response = fetch(wrapped_request, &mut None, new_fetch_context());
|
||||
let fetch_response = fetch_sync(request);
|
||||
let _ = server.close();
|
||||
|
||||
assert!(!fetch_response.is_network_error());
|
||||
|
@ -402,9 +392,7 @@ fn test_fetch_response_is_opaque_filtered() {
|
|||
let origin = Origin::Origin(UrlOrigin::new_opaque());
|
||||
let mut request = Request::new(url, Some(origin), false);
|
||||
*request.referer.borrow_mut() = Referer::NoReferer;
|
||||
let wrapped_request = Rc::new(request);
|
||||
|
||||
let fetch_response = fetch(wrapped_request, &mut None, new_fetch_context());
|
||||
let fetch_response = fetch_sync(request);
|
||||
let _ = server.close();
|
||||
|
||||
assert!(!fetch_response.is_network_error());
|
||||
|
@ -452,9 +440,7 @@ fn test_fetch_response_is_opaque_redirect_filtered() {
|
|||
let mut request = Request::new(url, Some(origin), false);
|
||||
*request.referer.borrow_mut() = Referer::NoReferer;
|
||||
request.redirect_mode.set(RedirectMode::Manual);
|
||||
let wrapped_request = Rc::new(request);
|
||||
|
||||
let fetch_response = fetch(wrapped_request, &mut None, new_fetch_context());
|
||||
let fetch_response = fetch_sync(request);
|
||||
let _ = server.close();
|
||||
|
||||
assert!(!fetch_response.is_network_error());
|
||||
|
@ -491,8 +477,7 @@ fn test_fetch_with_local_urls_only() {
|
|||
// Set the flag.
|
||||
request.local_urls_only = true;
|
||||
|
||||
let wrapped_request = Rc::new(request);
|
||||
fetch(wrapped_request, &mut None, new_fetch_context())
|
||||
fetch_sync(request)
|
||||
};
|
||||
|
||||
let local_url = Url::parse("about:blank").unwrap();
|
||||
|
@ -529,9 +514,7 @@ fn setup_server_and_fetch(message: &'static [u8], redirect_cap: u32) -> Response
|
|||
let origin = Origin::Origin(url.origin());
|
||||
let mut request = Request::new(url, Some(origin), false);
|
||||
*request.referer.borrow_mut() = Referer::NoReferer;
|
||||
let wrapped_request = Rc::new(request);
|
||||
|
||||
let fetch_response = fetch(wrapped_request, &mut None, new_fetch_context());
|
||||
let fetch_response = fetch_sync(request);
|
||||
let _ = server.close();
|
||||
fetch_response
|
||||
}
|
||||
|
@ -615,9 +598,8 @@ fn test_fetch_redirect_updates_method_runner(tx: Sender<bool>, status_code: Stat
|
|||
let mut request = Request::new(url, Some(origin), false);
|
||||
*request.referer.borrow_mut() = Referer::NoReferer;
|
||||
*request.method.borrow_mut() = method;
|
||||
let wrapped_request = Rc::new(request);
|
||||
|
||||
let _ = fetch(wrapped_request, &mut None, new_fetch_context());
|
||||
let _ = fetch_sync(request);
|
||||
let _ = server.close();
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue