aboutsummaryrefslogtreecommitdiffstats
path: root/components/net/fetch/methods.rs
diff options
context:
space:
mode:
authormrnayak <rmuddur@gmail.com>2017-01-08 08:52:18 +0530
committermrnayak <rmuddur@gmail.com>2017-01-08 08:52:18 +0530
commita3026499f43860c0d02170534bee20f8f5cc7faa (patch)
treeed575e0f6388fc082ca505dc094675e6ae707279 /components/net/fetch/methods.rs
parent496447a363ca4fc5d6789241ccb0b94134917b9a (diff)
downloadservo-a3026499f43860c0d02170534bee20f8f5cc7faa.tar.gz
servo-a3026499f43860c0d02170534bee20f8f5cc7faa.zip
Implement Subresource Integrity
Implemented response validation part of https://w3c.github.io/webappsec-subresource-integrity/. Implemented step eighteen of the main fetch. If a request has integrity metadata, then following steps are performed *Wait for response body *If the response does not have a termination reason and response does not match request’s integrity metadata, set response to a network error.# Please enter the commit message for your changes. Lines starting
Diffstat (limited to 'components/net/fetch/methods.rs')
-rw-r--r--components/net/fetch/methods.rs78
1 files changed, 35 insertions, 43 deletions
diff --git a/components/net/fetch/methods.rs b/components/net/fetch/methods.rs
index 0a284ee4016..44a603025b0 100644
--- a/components/net/fetch/methods.rs
+++ b/components/net/fetch/methods.rs
@@ -24,6 +24,7 @@ use std::io::Read;
use std::mem;
use std::rc::Rc;
use std::sync::mpsc::{Sender, Receiver};
+use subresource_integrity::is_response_integrity_valid;
pub type Target<'a> = &'a mut (FetchTaskTarget + Send);
@@ -268,6 +269,7 @@ pub fn main_fetch(request: Rc<Request>,
response
};
+ let mut response_loaded = false;
{
// Step 14
let network_error_res;
@@ -297,50 +299,33 @@ pub fn main_fetch(request: Rc<Request>,
let mut body = internal_response.body.lock().unwrap();
*body = ResponseBody::Empty;
}
-
- // Step 18
- // TODO be able to compare response integrity against request integrity metadata
- // if !response.is_network_error() {
-
- // // Substep 1
- // response.wait_until_done();
-
- // // Substep 2
- // if response.termination_reason.is_none() {
- // response = Response::network_error();
- // internal_response = Response::network_error();
- // }
- // }
}
+ // Step 18
+ let response = if !response.is_network_error() && *request.integrity_metadata.borrow() != "" {
+ // Substep 1
+ wait_for_response(&response, target, done_chan);
+ response_loaded = true;
+
+ // Substep 2
+ let ref integrity_metadata = *request.integrity_metadata.borrow();
+ if response.termination_reason.is_none() &&
+ !is_response_integrity_valid(integrity_metadata, &response) {
+ Response::network_error(NetworkError::Internal("Subresource integrity validation failed".into()))
+ } else {
+ response
+ }
+ } else {
+ response
+ };
// Step 19
if request.synchronous {
// process_response is not supposed to be used
// by sync fetch, but we overload it here for simplicity
target.process_response(&response);
-
- if let Some(ref ch) = *done_chan {
- loop {
- match ch.1.recv()
- .expect("fetch worker should always send Done before terminating") {
- Data::Payload(vec) => {
- target.process_response_chunk(vec);
- }
- Data::Done => break,
- }
- }
- } else {
- let body = response.body.lock().unwrap();
- if let ResponseBody::Done(ref vec) = *body {
- // in case there was no channel to wait for, the body was
- // 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!(*body == ResponseBody::Empty)
- }
+ if !response_loaded {
+ wait_for_response(&response, target, done_chan);
}
-
// overloaded similarly to process_response
target.process_response_eof(&response);
return response;
@@ -360,13 +345,25 @@ pub fn main_fetch(request: Rc<Request>,
target.process_response(&response);
// Step 22
+ if !response_loaded {
+ wait_for_response(&response, target, done_chan);
+ }
+
+ // Step 24
+ target.process_response_eof(&response);
+
+ // TODO remove this line when only asynchronous fetches are used
+ return response;
+}
+
+fn wait_for_response(response: &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") {
Data::Payload(vec) => {
target.process_response_chunk(vec);
- }
+ },
Data::Done => break,
}
}
@@ -381,12 +378,6 @@ pub fn main_fetch(request: Rc<Request>,
assert!(*body == ResponseBody::Empty)
}
}
-
- // Step 24
- target.process_response_eof(&response);
-
- // TODO remove this line when only asynchronous fetches are used
- return response;
}
/// [Basic fetch](https://fetch.spec.whatwg.org#basic-fetch)
@@ -518,3 +509,4 @@ fn is_null_body_status(status: &Option<StatusCode>) -> bool {
_ => false
}
}
+