diff options
Diffstat (limited to 'components')
-rw-r--r-- | components/net/fetch/methods.rs | 89 | ||||
-rw-r--r-- | components/net/filemanager_thread.rs | 34 |
2 files changed, 77 insertions, 46 deletions
diff --git a/components/net/fetch/methods.rs b/components/net/fetch/methods.rs index c5e6e45dde5..fe6400822ed 100644 --- a/components/net/fetch/methods.rs +++ b/components/net/fetch/methods.rs @@ -4,7 +4,7 @@ use crate::data_loader::decode; use crate::fetch::cors_cache::CorsCache; -use crate::filemanager_thread::{fetch_file_in_chunks, FILE_CHUNK_SIZE, FileManager}; +use crate::filemanager_thread::{fetch_file_in_chunks, FileManager, FILE_CHUNK_SIZE}; use crate::http_loader::{determine_request_referrer, http_fetch, HttpState}; use crate::http_loader::{set_default_accept, set_default_accept_language}; use crate::subresource_integrity::is_response_integrity_valid; @@ -26,7 +26,7 @@ use net_traits::response::{Response, ResponseBody, ResponseType}; use net_traits::{FetchTaskTarget, NetworkError, ReferrerPolicy, ResourceFetchTiming}; use servo_url::ServoUrl; use std::borrow::Cow; -use std::fs::{File, Metadata}; +use std::fs::File; use std::io::{BufReader, Seek, SeekFrom}; use std::mem; use std::ops::Bound; @@ -490,10 +490,34 @@ fn wait_for_response(response: &mut Response, target: Target, done_chan: &mut Do } } +/// Range header start and end values. +pub enum RangeRequestBounds { + /// The range bounds are known and set to final values. + Final(RelativePos), + /// We need extra information to set the range bounds. + /// i.e. buffer or file size. + Pending(u64), +} + +impl RangeRequestBounds { + pub fn get_final(&self, len: Option<u64>) -> RelativePos { + match self { + RangeRequestBounds::Final(pos) => pos.clone(), + RangeRequestBounds::Pending(offset) => RelativePos::from_opts( + if let Some(len) = len { + Some((len - u64::min(len, *offset)) as i64) + } else { + Some(0) + }, + None, + ), + } + } +} + /// Get the range bounds if the `Range` header is present. -fn get_range_bounds(range: Option<Range>, metadata: Option<Metadata>) -> RelativePos { - if let Some(ref range) = range - { +fn get_range_request_bounds(range: Option<Range>) -> RangeRequestBounds { + if let Some(ref range) = range { let (start, end) = match range .iter() .collect::<Vec<(Bound<u64>, Bound<u64>)>>() @@ -505,18 +529,13 @@ fn get_range_bounds(range: Option<Range>, metadata: Option<Metadata>) -> Relativ (start, Some(i64::max(start as i64, end as i64))) }, Some(&(Bound::Unbounded, Bound::Included(offset))) => { - if let Some(metadata) = metadata { - // `offset` cannot be bigger than the file size. - (metadata.len() - u64::min(metadata.len(), offset), None) - } else { - (0, None) - } + return RangeRequestBounds::Pending(offset); }, _ => (0, None), }; - RelativePos::from_opts(Some(start as i64), end) + RangeRequestBounds::Final(RelativePos::from_opts(Some(start as i64), end)) } else { - RelativePos::from_opts(Some(0), None) + RangeRequestBounds::Final(RelativePos::from_opts(Some(0), None)) } } @@ -569,12 +588,17 @@ fn scheme_fetch( // Get range bounds (if any) and try to seek to the requested offset. // If seeking fails, bail out with a NetworkError. - let range = get_range_bounds(request.headers.typed_get::<Range>(), file.metadata().ok()); + let file_size = match file.metadata() { + Ok(metadata) => Some(metadata.len()), + Err(_) => None, + }; + let range = get_range_request_bounds(request.headers.typed_get::<Range>()); + let range = range.get_final(file_size); let mut reader = BufReader::with_capacity(FILE_CHUNK_SIZE, file); if reader.seek(SeekFrom::Start(range.start as u64)).is_err() { *response.body.lock().unwrap() = ResponseBody::Done(vec![]); return Response::network_error(NetworkError::Internal( - "Unexpected method for blob".into(), + "Unexpected method for file".into(), )); } @@ -588,11 +612,13 @@ fn scheme_fetch( *done_chan = Some((done_sender.clone(), done_receiver)); *response.body.lock().unwrap() = ResponseBody::Receiving(vec![]); - fetch_file_in_chunks(done_sender, - reader, - response.body.clone(), - context.cancellation_listener.clone(), - range); + fetch_file_in_chunks( + done_sender, + reader, + response.body.clone(), + context.cancellation_listener.clone(), + range, + ); response } else { @@ -614,12 +640,14 @@ fn scheme_fetch( )); } - let range = get_range_bounds(request.headers.typed_get::<Range>(), None); + let range = get_range_request_bounds(request.headers.typed_get::<Range>()); let (id, origin) = match parse_blob_url(&url) { Ok((id, origin)) => (id, origin), Err(()) => { - return Response::network_error(NetworkError::Internal("Invalid blob url".into())); + return Response::network_error(NetworkError::Internal( + "Invalid blob url".into(), + )); }, }; @@ -628,14 +656,15 @@ fn scheme_fetch( *done_chan = Some((done_sender.clone(), done_receiver)); *response.body.lock().unwrap() = ResponseBody::Receiving(vec![]); let check_url_validity = true; - if let Err(err) = context.filemanager.fetch_file(&done_sender, - context.cancellation_listener.clone(), - id, - check_url_validity, - origin, - &mut response, - range) - { + if let Err(err) = context.filemanager.fetch_file( + &done_sender, + context.cancellation_listener.clone(), + id, + check_url_validity, + origin, + &mut response, + range, + ) { let _ = done_sender.send(Data::Done); return Response::network_error(NetworkError::Internal(err)); }; diff --git a/components/net/filemanager_thread.rs b/components/net/filemanager_thread.rs index 032199d3f43..f70d774e95e 100644 --- a/components/net/filemanager_thread.rs +++ b/components/net/filemanager_thread.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use crate::fetch::methods::{CancellationListener, Data}; +use crate::fetch::methods::{CancellationListener, Data, RangeRequestBounds}; use embedder_traits::{EmbedderMsg, EmbedderProxy, FilterPattern}; use headers_ext::{ContentLength, ContentType, HeaderMap, HeaderMapExt}; use http::header::{self, HeaderValue}; @@ -113,7 +113,7 @@ impl FileManager { check_url_validity: bool, origin: FileOrigin, response: &mut Response, - range: RelativePos + range: RangeRequestBounds, ) -> Result<(), String> { self.store .fetch_blob_buf( @@ -532,13 +532,14 @@ impl FileManagerStore { cancellation_listener: Arc<Mutex<CancellationListener>>, id: &Uuid, origin_in: &FileOrigin, - range: RelativePos, + range: RangeRequestBounds, check_url_validity: bool, response: &mut Response, ) -> Result<(), BlobURLStoreError> { let file_impl = self.get_impl(id, origin_in, check_url_validity)?; match file_impl { FileImpl::Memory(buf) => { + let range = range.get_final(Some(buf.size)); let range = range.to_abs_range(buf.size as usize); let len = range.len() as u64; @@ -567,9 +568,12 @@ impl FileManagerStore { let file = File::open(&metadata.path) .map_err(|e| BlobURLStoreError::External(e.to_string()))?; + let range = range.get_final(Some(metadata.size)); let mut reader = BufReader::with_capacity(FILE_CHUNK_SIZE, file); if reader.seek(SeekFrom::Start(range.start as u64)).is_err() { - return Err(BlobURLStoreError::External("Unexpected method for blob".into())); + return Err(BlobURLStoreError::External( + "Unexpected method for blob".into(), + )); } let filename = metadata @@ -585,11 +589,13 @@ impl FileManagerStore { filename, ); - fetch_file_in_chunks(done_sender.clone(), - reader, - response.body.clone(), - cancellation_listener, - range); + fetch_file_in_chunks( + done_sender.clone(), + reader, + response.body.clone(), + cancellation_listener, + range, + ); Ok(()) }, @@ -601,7 +607,7 @@ impl FileManagerStore { cancellation_listener, &parent_id, origin_in, - range.slice_inner(&inner_rel_pos), + RangeRequestBounds::Final(range.get_final(None).slice_inner(&inner_rel_pos)), false, response, ); @@ -794,9 +800,7 @@ pub fn fetch_file_in_chunks( let length = { let buffer = reader.fill_buf().unwrap().to_vec(); let mut buffer_len = buffer.len(); - if let ResponseBody::Receiving(ref mut body) = - *res_body.lock().unwrap() - { + if let ResponseBody::Receiving(ref mut body) = *res_body.lock().unwrap() { let offset = usize::min( { if let Some(end) = range.end { @@ -824,9 +828,7 @@ pub fn fetch_file_in_chunks( if length == 0 { let mut body = res_body.lock().unwrap(); let completed_body = match *body { - ResponseBody::Receiving(ref mut body) => { - mem::replace(body, vec![]) - }, + ResponseBody::Receiving(ref mut body) => mem::replace(body, vec![]), _ => vec![], }; *body = ResponseBody::Done(completed_body); |