mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
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:
commit
1343c7de50
1 changed files with 46 additions and 5 deletions
|
@ -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())),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue