mirror of
https://github.com/servo/servo.git
synced 2025-08-02 20:20:14 +01:00
Rustfmt net crate
This commit is contained in:
parent
ba1ed11ced
commit
2481ad25f8
30 changed files with 4957 additions and 2870 deletions
|
@ -35,7 +35,8 @@ use std::thread;
|
|||
use subresource_integrity::is_response_integrity_valid;
|
||||
|
||||
lazy_static! {
|
||||
static ref X_CONTENT_TYPE_OPTIONS: HeaderName = HeaderName::from_static("x-content-type-options");
|
||||
static ref X_CONTENT_TYPE_OPTIONS: HeaderName =
|
||||
HeaderName::from_static("x-content-type-options");
|
||||
}
|
||||
|
||||
const FILE_CHUNK_SIZE: usize = 32768; //32 KB
|
||||
|
@ -87,16 +88,16 @@ impl CancellationListener {
|
|||
pub type DoneChannel = Option<(Sender<Data>, Receiver<Data>)>;
|
||||
|
||||
/// [Fetch](https://fetch.spec.whatwg.org#concept-fetch)
|
||||
pub fn fetch(request: &mut Request,
|
||||
target: Target,
|
||||
context: &FetchContext) {
|
||||
pub fn fetch(request: &mut Request, target: Target, context: &FetchContext) {
|
||||
fetch_with_cors_cache(request, &mut CorsCache::new(), target, context);
|
||||
}
|
||||
|
||||
pub fn fetch_with_cors_cache(request: &mut Request,
|
||||
cache: &mut CorsCache,
|
||||
target: Target,
|
||||
context: &FetchContext) {
|
||||
pub fn fetch_with_cors_cache(
|
||||
request: &mut Request,
|
||||
cache: &mut CorsCache,
|
||||
target: Target,
|
||||
context: &FetchContext,
|
||||
) {
|
||||
// Step 1.
|
||||
if request.window == Window::Client {
|
||||
// TODO: Set window to request's client object if client is a Window object
|
||||
|
@ -132,21 +133,27 @@ pub fn fetch_with_cors_cache(request: &mut Request,
|
|||
}
|
||||
|
||||
/// [Main fetch](https://fetch.spec.whatwg.org/#concept-main-fetch)
|
||||
pub fn main_fetch(request: &mut Request,
|
||||
cache: &mut CorsCache,
|
||||
cors_flag: bool,
|
||||
recursive_flag: bool,
|
||||
target: Target,
|
||||
done_chan: &mut DoneChannel,
|
||||
context: &FetchContext)
|
||||
-> Response {
|
||||
pub fn main_fetch(
|
||||
request: &mut Request,
|
||||
cache: &mut CorsCache,
|
||||
cors_flag: bool,
|
||||
recursive_flag: bool,
|
||||
target: Target,
|
||||
done_chan: &mut DoneChannel,
|
||||
context: &FetchContext,
|
||||
) -> Response {
|
||||
// Step 1.
|
||||
let mut response = None;
|
||||
|
||||
// Step 2.
|
||||
if request.local_urls_only {
|
||||
if !matches!(request.current_url().scheme(), "about" | "blob" | "data" | "filesystem") {
|
||||
response = Some(Response::network_error(NetworkError::Internal("Non-local scheme".into())));
|
||||
if !matches!(
|
||||
request.current_url().scheme(),
|
||||
"about" | "blob" | "data" | "filesystem"
|
||||
) {
|
||||
response = Some(Response::network_error(NetworkError::Internal(
|
||||
"Non-local scheme".into(),
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -158,7 +165,9 @@ pub fn main_fetch(request: &mut Request,
|
|||
|
||||
// Step 5.
|
||||
if should_be_blocked_due_to_bad_port(&request.current_url()) {
|
||||
response = Some(Response::network_error(NetworkError::Internal("Request attempted on bad port".into())));
|
||||
response = Some(Response::network_error(NetworkError::Internal(
|
||||
"Request attempted on bad port".into(),
|
||||
)));
|
||||
}
|
||||
// TODO: handle blocking as mixed content.
|
||||
// TODO: handle blocking by content security policy.
|
||||
|
@ -167,7 +176,9 @@ pub fn main_fetch(request: &mut Request,
|
|||
// TODO: handle request's client's referrer policy.
|
||||
|
||||
// Step 7.
|
||||
request.referrer_policy = request.referrer_policy.or(Some(ReferrerPolicy::NoReferrerWhenDowngrade));
|
||||
request.referrer_policy = request
|
||||
.referrer_policy
|
||||
.or(Some(ReferrerPolicy::NoReferrerWhenDowngrade));
|
||||
|
||||
// Step 8.
|
||||
{
|
||||
|
@ -182,11 +193,13 @@ pub fn main_fetch(request: &mut Request,
|
|||
Referrer::ReferrerUrl(url) => {
|
||||
request.headers.remove(header::REFERER);
|
||||
let current_url = request.current_url().clone();
|
||||
determine_request_referrer(&mut request.headers,
|
||||
request.referrer_policy.unwrap(),
|
||||
url,
|
||||
current_url)
|
||||
}
|
||||
determine_request_referrer(
|
||||
&mut request.headers,
|
||||
request.referrer_policy.unwrap(),
|
||||
url,
|
||||
current_url,
|
||||
)
|
||||
},
|
||||
};
|
||||
if let Some(referrer_url) = referrer_url {
|
||||
request.referrer = Referrer::ReferrerUrl(referrer_url);
|
||||
|
@ -197,8 +210,12 @@ pub fn main_fetch(request: &mut Request,
|
|||
// TODO: handle FTP URLs.
|
||||
|
||||
// Step 10.
|
||||
context.state.hsts_list.read().unwrap().switch_known_hsts_host_domain_url_to_https(
|
||||
request.current_url_mut());
|
||||
context
|
||||
.state
|
||||
.hsts_list
|
||||
.read()
|
||||
.unwrap()
|
||||
.switch_known_hsts_host_domain_url_to_https(request.current_url_mut());
|
||||
|
||||
// Step 11.
|
||||
// Not applicable: see fetch_async.
|
||||
|
@ -218,47 +235,48 @@ pub fn main_fetch(request: &mut Request,
|
|||
// and about: schemes, but CSS tests will break on loading Ahem
|
||||
// since we load them through a file: URL.
|
||||
current_url.scheme() == "about" ||
|
||||
request.mode == RequestMode::Navigate {
|
||||
request.mode == RequestMode::Navigate
|
||||
{
|
||||
// Substep 1.
|
||||
request.response_tainting = ResponseTainting::Basic;
|
||||
|
||||
// Substep 2.
|
||||
scheme_fetch(request, cache, target, done_chan, context)
|
||||
|
||||
} else if request.mode == RequestMode::SameOrigin {
|
||||
Response::network_error(NetworkError::Internal("Cross-origin response".into()))
|
||||
|
||||
} else if request.mode == RequestMode::NoCors {
|
||||
// Substep 1.
|
||||
request.response_tainting = ResponseTainting::Opaque;
|
||||
|
||||
// Substep 2.
|
||||
scheme_fetch(request, cache, target, done_chan, context)
|
||||
|
||||
} else if !matches!(current_url.scheme(), "http" | "https") {
|
||||
Response::network_error(NetworkError::Internal("Non-http scheme".into()))
|
||||
|
||||
} else if request.use_cors_preflight ||
|
||||
(request.unsafe_request &&
|
||||
(!is_cors_safelisted_method(&request.method) ||
|
||||
request.headers.iter().any(|(name, value)| !is_cors_safelisted_request_header(&name, &value)))) {
|
||||
request.headers.iter().any(|(name, value)| {
|
||||
!is_cors_safelisted_request_header(&name, &value)
|
||||
}))) {
|
||||
// Substep 1.
|
||||
request.response_tainting = ResponseTainting::CorsTainting;
|
||||
// Substep 2.
|
||||
let response = http_fetch(request, cache, true, true, false,
|
||||
target, done_chan, context);
|
||||
let response = http_fetch(
|
||||
request, cache, true, true, false, target, done_chan, context,
|
||||
);
|
||||
// Substep 3.
|
||||
if response.is_network_error() {
|
||||
// TODO clear cache entries using request
|
||||
}
|
||||
// Substep 4.
|
||||
response
|
||||
|
||||
} else {
|
||||
// Substep 1.
|
||||
request.response_tainting = ResponseTainting::CorsTainting;
|
||||
// Substep 2.
|
||||
http_fetch(request, cache, true, false, false, target, done_chan, context)
|
||||
http_fetch(
|
||||
request, cache, true, false, false, target, done_chan, context,
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -272,19 +290,25 @@ pub fn main_fetch(request: &mut Request,
|
|||
// Substep 1.
|
||||
if request.response_tainting == ResponseTainting::CorsTainting {
|
||||
// Subsubstep 1.
|
||||
let header_names: Option<Vec<HeaderName>> = response.headers.typed_get::<AccessControlExposeHeaders>()
|
||||
let header_names: Option<Vec<HeaderName>> = response
|
||||
.headers
|
||||
.typed_get::<AccessControlExposeHeaders>()
|
||||
.map(|v| v.iter().collect());
|
||||
match header_names {
|
||||
// Subsubstep 2.
|
||||
Some(ref list) if request.credentials_mode != CredentialsMode::Include => {
|
||||
if list.len() == 1 && list[0] == "*" {
|
||||
response.cors_exposed_header_name_list =
|
||||
response.headers.iter().map(|(name, _)| name.as_str().to_owned()).collect();
|
||||
response.cors_exposed_header_name_list = response
|
||||
.headers
|
||||
.iter()
|
||||
.map(|(name, _)| name.as_str().to_owned())
|
||||
.collect();
|
||||
}
|
||||
},
|
||||
// Subsubstep 3.
|
||||
Some(list) => {
|
||||
response.cors_exposed_header_name_list = list.iter().map(|h| h.as_str().to_owned()).collect();
|
||||
response.cors_exposed_header_name_list =
|
||||
list.iter().map(|h| h.as_str().to_owned()).collect();
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
|
@ -304,13 +328,16 @@ pub fn main_fetch(request: &mut Request,
|
|||
let internal_error = {
|
||||
// Tests for steps 17 and 18, before step 15 for borrowing concerns.
|
||||
let response_is_network_error = response.is_network_error();
|
||||
let should_replace_with_nosniff_error =
|
||||
!response_is_network_error && should_be_blocked_due_to_nosniff(request.destination, &response.headers);
|
||||
let should_replace_with_mime_type_error =
|
||||
!response_is_network_error && should_be_blocked_due_to_mime_type(request.destination, &response.headers);
|
||||
let should_replace_with_nosniff_error = !response_is_network_error &&
|
||||
should_be_blocked_due_to_nosniff(request.destination, &response.headers);
|
||||
let should_replace_with_mime_type_error = !response_is_network_error &&
|
||||
should_be_blocked_due_to_mime_type(request.destination, &response.headers);
|
||||
|
||||
// Step 15.
|
||||
let mut network_error_response = response.get_network_error().cloned().map(Response::network_error);
|
||||
let mut network_error_response = response
|
||||
.get_network_error()
|
||||
.cloned()
|
||||
.map(Response::network_error);
|
||||
let internal_response = if let Some(error_response) = network_error_response.as_mut() {
|
||||
error_response
|
||||
} else {
|
||||
|
@ -326,27 +353,30 @@ pub fn main_fetch(request: &mut Request,
|
|||
// TODO: handle blocking as mixed content.
|
||||
// TODO: handle blocking by content security policy.
|
||||
let blocked_error_response;
|
||||
let internal_response =
|
||||
if should_replace_with_nosniff_error {
|
||||
// Defer rebinding result
|
||||
blocked_error_response = Response::network_error(NetworkError::Internal("Blocked by nosniff".into()));
|
||||
&blocked_error_response
|
||||
} else if should_replace_with_mime_type_error {
|
||||
// Defer rebinding result
|
||||
blocked_error_response = Response::network_error(NetworkError::Internal("Blocked by mime type".into()));
|
||||
&blocked_error_response
|
||||
} else {
|
||||
internal_response
|
||||
};
|
||||
let internal_response = if should_replace_with_nosniff_error {
|
||||
// Defer rebinding result
|
||||
blocked_error_response =
|
||||
Response::network_error(NetworkError::Internal("Blocked by nosniff".into()));
|
||||
&blocked_error_response
|
||||
} else if should_replace_with_mime_type_error {
|
||||
// Defer rebinding result
|
||||
blocked_error_response =
|
||||
Response::network_error(NetworkError::Internal("Blocked by mime type".into()));
|
||||
&blocked_error_response
|
||||
} else {
|
||||
internal_response
|
||||
};
|
||||
|
||||
// Step 18.
|
||||
// We check `internal_response` since we did not mutate `response`
|
||||
// in the previous step.
|
||||
let not_network_error = !response_is_network_error && !internal_response.is_network_error();
|
||||
if not_network_error && (is_null_body_status(&internal_response.status) ||
|
||||
match request.method {
|
||||
Method::HEAD | Method::CONNECT => true,
|
||||
_ => false }) {
|
||||
if not_network_error &&
|
||||
(is_null_body_status(&internal_response.status) ||
|
||||
match request.method {
|
||||
Method::HEAD | Method::CONNECT => true,
|
||||
_ => false,
|
||||
}) {
|
||||
// when Fetch is used only asynchronously, we will need to make sure
|
||||
// that nothing tries to write to the body at this point
|
||||
let mut body = internal_response.body.lock().unwrap();
|
||||
|
@ -373,8 +403,11 @@ pub fn main_fetch(request: &mut Request,
|
|||
// Step 19.2.
|
||||
let ref integrity_metadata = &request.integrity_metadata;
|
||||
if response.termination_reason.is_none() &&
|
||||
!is_response_integrity_valid(integrity_metadata, &response) {
|
||||
Response::network_error(NetworkError::Internal("Subresource integrity validation failed".into()))
|
||||
!is_response_integrity_valid(integrity_metadata, &response)
|
||||
{
|
||||
Response::network_error(NetworkError::Internal(
|
||||
"Subresource integrity validation failed".into(),
|
||||
))
|
||||
} else {
|
||||
response
|
||||
}
|
||||
|
@ -410,7 +443,7 @@ pub fn main_fetch(request: &mut Request,
|
|||
|
||||
// Step 23.
|
||||
if !response_loaded {
|
||||
wait_for_response(&mut response, target, done_chan);
|
||||
wait_for_response(&mut response, target, done_chan);
|
||||
}
|
||||
|
||||
// Step 24.
|
||||
|
@ -430,8 +463,11 @@ pub fn main_fetch(request: &mut Request,
|
|||
fn wait_for_response(response: &mut Response, target: Target, done_chan: &mut DoneChannel) {
|
||||
if let Some(ref ch) = *done_chan {
|
||||
loop {
|
||||
match ch.1.recv()
|
||||
.expect("fetch worker should always send Done before terminating") {
|
||||
match ch
|
||||
.1
|
||||
.recv()
|
||||
.expect("fetch worker should always send Done before terminating")
|
||||
{
|
||||
Data::Payload(vec) => {
|
||||
target.process_response_chunk(vec);
|
||||
},
|
||||
|
@ -439,7 +475,7 @@ fn wait_for_response(response: &mut Response, target: Target, done_chan: &mut Do
|
|||
Data::Cancelled => {
|
||||
response.aborted.store(true, Ordering::Relaxed);
|
||||
break;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -456,36 +492,39 @@ fn wait_for_response(response: &mut Response, target: Target, done_chan: &mut Do
|
|||
}
|
||||
|
||||
/// [Scheme fetch](https://fetch.spec.whatwg.org#scheme-fetch)
|
||||
fn scheme_fetch(request: &mut Request,
|
||||
cache: &mut CorsCache,
|
||||
target: Target,
|
||||
done_chan: &mut DoneChannel,
|
||||
context: &FetchContext)
|
||||
-> Response {
|
||||
fn scheme_fetch(
|
||||
request: &mut Request,
|
||||
cache: &mut CorsCache,
|
||||
target: Target,
|
||||
done_chan: &mut DoneChannel,
|
||||
context: &FetchContext,
|
||||
) -> Response {
|
||||
let url = request.current_url();
|
||||
|
||||
match url.scheme() {
|
||||
"about" if url.path() == "blank" => {
|
||||
let mut response = Response::new(url);
|
||||
response.headers.typed_insert(ContentType::from(mime::TEXT_HTML_UTF_8));
|
||||
response
|
||||
.headers
|
||||
.typed_insert(ContentType::from(mime::TEXT_HTML_UTF_8));
|
||||
*response.body.lock().unwrap() = ResponseBody::Done(vec![]);
|
||||
response
|
||||
},
|
||||
|
||||
"http" | "https" => {
|
||||
http_fetch(request, cache, false, false, false, target, done_chan, context)
|
||||
},
|
||||
"http" | "https" => http_fetch(
|
||||
request, cache, false, false, false, target, done_chan, context,
|
||||
),
|
||||
|
||||
"data" => {
|
||||
match decode(&url) {
|
||||
Ok((mime, bytes)) => {
|
||||
let mut response = Response::new(url);
|
||||
*response.body.lock().unwrap() = ResponseBody::Done(bytes);
|
||||
response.headers.typed_insert(ContentType::from(mime));
|
||||
response
|
||||
},
|
||||
Err(_) => Response::network_error(NetworkError::Internal("Decoding data URL failed".into()))
|
||||
}
|
||||
"data" => match decode(&url) {
|
||||
Ok((mime, bytes)) => {
|
||||
let mut response = Response::new(url);
|
||||
*response.body.lock().unwrap() = ResponseBody::Done(bytes);
|
||||
response.headers.typed_insert(ContentType::from(mime));
|
||||
response
|
||||
},
|
||||
Err(_) => {
|
||||
Response::network_error(NetworkError::Internal("Decoding data URL failed".into()))
|
||||
},
|
||||
},
|
||||
|
||||
"file" => {
|
||||
|
@ -507,9 +546,17 @@ fn scheme_fetch(request: &mut Request,
|
|||
|
||||
let cancellation_listener = context.cancellation_listener.clone();
|
||||
|
||||
let (start, end) = if let Some(ref range) = request.headers.typed_get::<Range>() {
|
||||
match range.iter().collect::<Vec<(Bound<u64>, Bound<u64>)>>().first() {
|
||||
Some(&(Bound::Included(start), Bound::Unbounded)) => (start, None),
|
||||
let (start, end) = if let Some(ref range) =
|
||||
request.headers.typed_get::<Range>()
|
||||
{
|
||||
match range
|
||||
.iter()
|
||||
.collect::<Vec<(Bound<u64>, Bound<u64>)>>()
|
||||
.first()
|
||||
{
|
||||
Some(&(Bound::Included(start), Bound::Unbounded)) => {
|
||||
(start, None)
|
||||
},
|
||||
Some(&(Bound::Included(start), Bound::Included(end))) => {
|
||||
// `end` should be less or equal to `start`.
|
||||
(start, Some(u64::max(start, end)))
|
||||
|
@ -517,75 +564,97 @@ fn scheme_fetch(request: &mut Request,
|
|||
Some(&(Bound::Unbounded, Bound::Included(offset))) => {
|
||||
if let Ok(metadata) = file.metadata() {
|
||||
// `offset` cannot be bigger than the file size.
|
||||
(metadata.len() - u64::min(metadata.len(), offset), None)
|
||||
(
|
||||
metadata.len() -
|
||||
u64::min(metadata.len(), offset),
|
||||
None,
|
||||
)
|
||||
} else {
|
||||
(0, None)
|
||||
}
|
||||
},
|
||||
_ => (0, None)
|
||||
_ => (0, None),
|
||||
}
|
||||
} else {
|
||||
(0, None)
|
||||
};
|
||||
|
||||
thread::Builder::new().name("fetch file worker thread".to_string()).spawn(move || {
|
||||
let mut reader = BufReader::with_capacity(FILE_CHUNK_SIZE, file);
|
||||
if reader.seek(SeekFrom::Start(start)).is_err() {
|
||||
warn!("Fetch - could not seek to {:?}", start);
|
||||
}
|
||||
thread::Builder::new()
|
||||
.name("fetch file worker thread".to_string())
|
||||
.spawn(move || {
|
||||
let mut reader =
|
||||
BufReader::with_capacity(FILE_CHUNK_SIZE, file);
|
||||
if reader.seek(SeekFrom::Start(start)).is_err() {
|
||||
warn!("Fetch - could not seek to {:?}", start);
|
||||
}
|
||||
|
||||
loop {
|
||||
if cancellation_listener.lock().unwrap().cancelled() {
|
||||
*res_body.lock().unwrap() = ResponseBody::Done(vec![]);
|
||||
let _ = done_sender.send(Data::Cancelled);
|
||||
return;
|
||||
}
|
||||
let length = {
|
||||
let mut buffer = reader.fill_buf().unwrap().to_vec();
|
||||
let mut buffer_len = buffer.len();
|
||||
if let ResponseBody::Receiving(ref mut body) = *res_body.lock().unwrap() {
|
||||
let offset = usize::min({
|
||||
if let Some(end) = end {
|
||||
let remaining_bytes =
|
||||
end as usize - start as usize - body.len();
|
||||
if remaining_bytes <= FILE_CHUNK_SIZE {
|
||||
// This is the last chunk so we set buffer len to 0 to break
|
||||
// the reading loop.
|
||||
buffer_len = 0;
|
||||
remaining_bytes
|
||||
} else {
|
||||
FILE_CHUNK_SIZE
|
||||
}
|
||||
} else {
|
||||
FILE_CHUNK_SIZE
|
||||
}
|
||||
}, buffer.len());
|
||||
body.extend_from_slice(&buffer[0..offset]);
|
||||
let _ = done_sender.send(Data::Payload(buffer));
|
||||
loop {
|
||||
if cancellation_listener.lock().unwrap().cancelled() {
|
||||
*res_body.lock().unwrap() =
|
||||
ResponseBody::Done(vec![]);
|
||||
let _ = done_sender.send(Data::Cancelled);
|
||||
return;
|
||||
}
|
||||
buffer_len
|
||||
};
|
||||
if length == 0 {
|
||||
let mut body = res_body.lock().unwrap();
|
||||
let completed_body = match *body {
|
||||
ResponseBody::Receiving(ref mut body) => {
|
||||
mem::replace(body, vec![])
|
||||
},
|
||||
_ => vec![],
|
||||
let length = {
|
||||
let mut buffer =
|
||||
reader.fill_buf().unwrap().to_vec();
|
||||
let mut buffer_len = buffer.len();
|
||||
if let ResponseBody::Receiving(ref mut body) =
|
||||
*res_body.lock().unwrap()
|
||||
{
|
||||
let offset = usize::min(
|
||||
{
|
||||
if let Some(end) = end {
|
||||
let remaining_bytes = end as usize -
|
||||
start as usize -
|
||||
body.len();
|
||||
if remaining_bytes <=
|
||||
FILE_CHUNK_SIZE
|
||||
{
|
||||
// This is the last chunk so we set buffer len to 0 to break
|
||||
// the reading loop.
|
||||
buffer_len = 0;
|
||||
remaining_bytes
|
||||
} else {
|
||||
FILE_CHUNK_SIZE
|
||||
}
|
||||
} else {
|
||||
FILE_CHUNK_SIZE
|
||||
}
|
||||
},
|
||||
buffer.len(),
|
||||
);
|
||||
body.extend_from_slice(&buffer[0..offset]);
|
||||
let _ = done_sender.send(Data::Payload(buffer));
|
||||
}
|
||||
buffer_len
|
||||
};
|
||||
*body = ResponseBody::Done(completed_body);
|
||||
let _ = done_sender.send(Data::Done);
|
||||
break;
|
||||
if length == 0 {
|
||||
let mut body = res_body.lock().unwrap();
|
||||
let completed_body = match *body {
|
||||
ResponseBody::Receiving(ref mut body) => {
|
||||
mem::replace(body, vec![])
|
||||
},
|
||||
_ => vec![],
|
||||
};
|
||||
*body = ResponseBody::Done(completed_body);
|
||||
let _ = done_sender.send(Data::Done);
|
||||
break;
|
||||
}
|
||||
reader.consume(length);
|
||||
}
|
||||
reader.consume(length);
|
||||
}
|
||||
}).expect("Failed to create fetch file worker thread");
|
||||
})
|
||||
.expect("Failed to create fetch file worker thread");
|
||||
response
|
||||
},
|
||||
_ => Response::network_error(NetworkError::Internal("Opening file failed".into())),
|
||||
_ => Response::network_error(NetworkError::Internal(
|
||||
"Opening file failed".into(),
|
||||
)),
|
||||
}
|
||||
},
|
||||
_ => Response::network_error(NetworkError::Internal("Constructing file path failed".into()))
|
||||
_ => Response::network_error(NetworkError::Internal(
|
||||
"Constructing file path failed".into(),
|
||||
)),
|
||||
}
|
||||
} else {
|
||||
Response::network_error(NetworkError::Internal("Unexpected method for file".into()))
|
||||
|
@ -596,7 +665,9 @@ fn scheme_fetch(request: &mut Request,
|
|||
println!("Loading blob {}", url.as_str());
|
||||
// Step 2.
|
||||
if request.method != Method::GET {
|
||||
return Response::network_error(NetworkError::Internal("Unexpected method for blob".into()));
|
||||
return Response::network_error(NetworkError::Internal(
|
||||
"Unexpected method for blob".into(),
|
||||
));
|
||||
}
|
||||
|
||||
match load_blob_sync(url.clone(), context.filemanager.clone()) {
|
||||
|
@ -618,7 +689,7 @@ fn scheme_fetch(request: &mut Request,
|
|||
Response::network_error(NetworkError::Internal("Unexpected scheme".into()))
|
||||
},
|
||||
|
||||
_ => Response::network_error(NetworkError::Internal("Unexpected scheme".into()))
|
||||
_ => Response::network_error(NetworkError::Internal("Unexpected scheme".into())),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -627,13 +698,15 @@ pub fn is_cors_safelisted_request_header(name: &HeaderName, value: &HeaderValue)
|
|||
if name == header::CONTENT_TYPE {
|
||||
if let Some(m) = value.to_str().ok().and_then(|s| s.parse::<Mime>().ok()) {
|
||||
m.type_() == mime::TEXT && m.subtype() == mime::PLAIN ||
|
||||
m.type_() == mime::APPLICATION && m.subtype() == mime::WWW_FORM_URLENCODED ||
|
||||
m.type_() == mime::MULTIPART && m.subtype() == mime::FORM_DATA
|
||||
m.type_() == mime::APPLICATION && m.subtype() == mime::WWW_FORM_URLENCODED ||
|
||||
m.type_() == mime::MULTIPART && m.subtype() == mime::FORM_DATA
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
name == header::ACCEPT || name == header::ACCEPT_LANGUAGE || name == header::CONTENT_LANGUAGE
|
||||
name == header::ACCEPT ||
|
||||
name == header::ACCEPT_LANGUAGE ||
|
||||
name == header::CONTENT_LANGUAGE
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -641,28 +714,35 @@ pub fn is_cors_safelisted_request_header(name: &HeaderName, value: &HeaderValue)
|
|||
pub fn is_cors_safelisted_method(m: &Method) -> bool {
|
||||
match *m {
|
||||
Method::GET | Method::HEAD | Method::POST => true,
|
||||
_ => false
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_null_body_status(status: &Option<(StatusCode, String)>) -> bool {
|
||||
match *status {
|
||||
Some((status, _)) => match status {
|
||||
StatusCode::SWITCHING_PROTOCOLS | StatusCode::NO_CONTENT |
|
||||
StatusCode::RESET_CONTENT | StatusCode::NOT_MODIFIED => true,
|
||||
_ => false
|
||||
StatusCode::SWITCHING_PROTOCOLS |
|
||||
StatusCode::NO_CONTENT |
|
||||
StatusCode::RESET_CONTENT |
|
||||
StatusCode::NOT_MODIFIED => true,
|
||||
_ => false,
|
||||
},
|
||||
_ => false
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://fetch.spec.whatwg.org/#should-response-to-request-be-blocked-due-to-nosniff?>
|
||||
pub fn should_be_blocked_due_to_nosniff(destination: Destination, response_headers: &HeaderMap) -> bool {
|
||||
pub fn should_be_blocked_due_to_nosniff(
|
||||
destination: Destination,
|
||||
response_headers: &HeaderMap,
|
||||
) -> bool {
|
||||
// Steps 1-3.
|
||||
// TODO(eijebong): Replace this once typed headers allow custom ones...
|
||||
if response_headers.get("x-content-type-options")
|
||||
.map_or(true, |val| val.to_str().unwrap_or("").to_lowercase() != "nosniff")
|
||||
{
|
||||
if response_headers
|
||||
.get("x-content-type-options")
|
||||
.map_or(true, |val| {
|
||||
val.to_str().unwrap_or("").to_lowercase() != "nosniff"
|
||||
}) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -692,30 +772,34 @@ pub fn should_be_blocked_due_to_nosniff(destination: Destination, response_heade
|
|||
"text/x-javascript".parse().unwrap(),
|
||||
];
|
||||
|
||||
javascript_mime_types.iter()
|
||||
javascript_mime_types
|
||||
.iter()
|
||||
.any(|mime| mime.type_() == mime_type.type_() && mime.subtype() == mime_type.subtype())
|
||||
}
|
||||
|
||||
match content_type_header {
|
||||
// Step 6
|
||||
Some(ref ct) if destination.is_script_like()
|
||||
=> !is_javascript_mime_type(&ct.clone().into()),
|
||||
Some(ref ct) if destination.is_script_like() => {
|
||||
!is_javascript_mime_type(&ct.clone().into())
|
||||
},
|
||||
|
||||
// Step 7
|
||||
Some(ref ct) if destination == Destination::Style
|
||||
=> {
|
||||
let m: mime::Mime = ct.clone().into();
|
||||
m.type_() != mime::TEXT && m.subtype() != mime::CSS
|
||||
},
|
||||
Some(ref ct) if destination == Destination::Style => {
|
||||
let m: mime::Mime = ct.clone().into();
|
||||
m.type_() != mime::TEXT && m.subtype() != mime::CSS
|
||||
},
|
||||
|
||||
None if destination == Destination::Style || destination.is_script_like() => true,
|
||||
// Step 8
|
||||
_ => false
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://fetch.spec.whatwg.org/#should-response-to-request-be-blocked-due-to-mime-type?>
|
||||
fn should_be_blocked_due_to_mime_type(destination: Destination, response_headers: &HeaderMap) -> bool {
|
||||
fn should_be_blocked_due_to_mime_type(
|
||||
destination: Destination,
|
||||
response_headers: &HeaderMap,
|
||||
) -> bool {
|
||||
// Step 1
|
||||
let mime_type: mime::Mime = match response_headers.typed_get::<ContentType>() {
|
||||
Some(header) => header.into(),
|
||||
|
@ -725,12 +809,10 @@ fn should_be_blocked_due_to_mime_type(destination: Destination, response_headers
|
|||
// Step 2-3
|
||||
destination.is_script_like() &&
|
||||
match mime_type.type_() {
|
||||
mime::AUDIO |
|
||||
mime::VIDEO |
|
||||
mime::IMAGE => true,
|
||||
mime::AUDIO | mime::VIDEO | mime::IMAGE => true,
|
||||
mime::TEXT if mime_type.subtype() == mime::CSV => true,
|
||||
// Step 4
|
||||
_ => false
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -745,14 +827,17 @@ pub fn should_be_blocked_due_to_bad_port(url: &ServoUrl) -> bool {
|
|||
// If there is no explicit port, this means the default one is used for
|
||||
// the given scheme, and thus this means the request should not be blocked
|
||||
// due to a bad port.
|
||||
let port = if let Some(port) = url.port() { port } else { return false };
|
||||
let port = if let Some(port) = url.port() {
|
||||
port
|
||||
} else {
|
||||
return false;
|
||||
};
|
||||
|
||||
// Step 4.
|
||||
if scheme == "ftp" && (port == 20 || port == 21) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Step 5.
|
||||
if is_network_scheme(scheme) && is_bad_port(port) {
|
||||
return true;
|
||||
|
@ -770,12 +855,10 @@ fn is_network_scheme(scheme: &str) -> bool {
|
|||
/// <https://fetch.spec.whatwg.org/#bad-port>
|
||||
fn is_bad_port(port: u16) -> bool {
|
||||
static BAD_PORTS: [u16; 64] = [
|
||||
1, 7, 9, 11, 13, 15, 17, 19, 20, 21, 22, 23, 25, 37, 42,
|
||||
43, 53, 77, 79, 87, 95, 101, 102, 103, 104, 109, 110, 111,
|
||||
113, 115, 117, 119, 123, 135, 139, 143, 179, 389, 465, 512,
|
||||
513, 514, 515, 526, 530, 531, 532, 540, 556, 563, 587, 601,
|
||||
636, 993, 995, 2049, 3659, 4045, 6000, 6665, 6666, 6667,
|
||||
6668, 6669
|
||||
1, 7, 9, 11, 13, 15, 17, 19, 20, 21, 22, 23, 25, 37, 42, 43, 53, 77, 79, 87, 95, 101, 102,
|
||||
103, 104, 109, 110, 111, 113, 115, 117, 119, 123, 135, 139, 143, 179, 389, 465, 512, 513,
|
||||
514, 515, 526, 530, 531, 532, 540, 556, 563, 587, 601, 636, 993, 995, 2049, 3659, 4045,
|
||||
6000, 6665, 6666, 6667, 6668, 6669,
|
||||
];
|
||||
|
||||
BAD_PORTS.binary_search(&port).is_ok()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue