Auto merge of #21560 - JacksonCoder:chunk-file, r=jdm

Read file URL in chunks

<!-- Please describe your changes on the following line: -->
This is a very straightforward PR: essentially, I replaced a `read_to_end` call that occurs when processing a file URL fetch with a loop that reads the file in chunks (with a `FILE_CHUNK_SIZE` constant that specifies the chunk size, which I've put at 32KB), and then calls `target.process_response_chunk` to process the chunk. The chunk is then appended to the fetch result, and once the end of the file is reached, the result is returned.

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix #21466.

<!-- Either: -->
- [ ] There are tests for these changes OR
- [X] These changes do not require tests because there isn't really a way to observe this.

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/21560)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2018-09-06 19:52:16 -04:00 committed by GitHub
commit 1343c7de50
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -25,14 +25,17 @@ use servo_url::ServoUrl;
use std::borrow::Cow; use std::borrow::Cow;
use std::fmt; use std::fmt;
use std::fs::File; use std::fs::File;
use std::io::Read; use std::io::{BufReader, BufRead};
use std::mem; use std::mem;
use std::str; use std::str;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use std::sync::mpsc::{Sender, Receiver}; use std::sync::mpsc::{Sender, Receiver, channel};
use std::thread;
use subresource_integrity::is_response_integrity_valid; use subresource_integrity::is_response_integrity_valid;
const FILE_CHUNK_SIZE: usize = 32768; //32 KB
pub type Target<'a> = &'a mut (FetchTaskTarget + Send); pub type Target<'a> = &'a mut (FetchTaskTarget + Send);
pub enum Data { pub enum Data {
@ -486,13 +489,51 @@ fn scheme_fetch(request: &mut Request,
Ok(file_path) => { Ok(file_path) => {
match File::open(file_path.clone()) { match File::open(file_path.clone()) {
Ok(mut file) => { Ok(mut file) => {
let mut bytes = vec![];
let _ = file.read_to_end(&mut bytes);
let mime = guess_mime_type(file_path); let mime = guess_mime_type(file_path);
let mut response = Response::new(url); let mut response = Response::new(url);
*response.body.lock().unwrap() = ResponseBody::Done(bytes);
response.headers.set(ContentType(mime)); response.headers.set(ContentType(mime));
let (done_sender, done_receiver) = channel();
*done_chan = Some((done_sender.clone(), done_receiver));
*response.body.lock().unwrap() = ResponseBody::Receiving(vec![]);
let mut res_body = response.body.clone();
let cancellation_listener = context.cancellation_listener.clone();
thread::Builder::new().name("fetch file worker thread".to_string()).spawn(move || {
let mut reader = BufReader::with_capacity(FILE_CHUNK_SIZE, file);
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 buffer_len = buffer.len();
if let ResponseBody::Receiving(ref mut body) = *res_body.lock().unwrap() {
body.extend_from_slice(&buffer);
let _ = done_sender.send(Data::Payload(buffer));
}
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![],
};
*body = ResponseBody::Done(completed_body);
let _ = done_sender.send(Data::Done);
break;
}
reader.consume(length);
}
}).expect("Failed to create fetch file worker thread");
response response
}, },
_ => Response::network_error(NetworkError::Internal("Opening file failed".into())), _ => Response::network_error(NetworkError::Internal("Opening file failed".into())),