diff options
-rw-r--r-- | components/net/filemanager_thread.rs | 49 | ||||
-rw-r--r-- | components/shared/net/filemanager_thread.rs | 10 | ||||
-rw-r--r-- | tests/wpt/meta/fetch/range/blob.any.js.ini | 24 | ||||
-rw-r--r-- | tests/wpt/meta/xhr/blob-range.any.js.ini | 20 | ||||
-rw-r--r-- | tests/wpt/mozilla/meta/MANIFEST.json | 7 | ||||
-rw-r--r-- | tests/wpt/mozilla/tests/mozilla/range_request_blob_url.html | 60 |
6 files changed, 75 insertions, 95 deletions
diff --git a/components/net/filemanager_thread.rs b/components/net/filemanager_thread.rs index b501d845c9b..e72290b2694 100644 --- a/components/net/filemanager_thread.rs +++ b/components/net/filemanager_thread.rs @@ -11,7 +11,7 @@ use std::sync::atomic::{self, AtomicBool, AtomicUsize, Ordering}; use std::sync::{Arc, Mutex, RwLock, Weak}; use embedder_traits::{EmbedderMsg, EmbedderProxy, FilterPattern}; -use headers::{ContentLength, ContentType, HeaderMap, HeaderMapExt, Range}; +use headers::{ContentLength, ContentRange, ContentType, HeaderMap, HeaderMapExt, Range}; use http::header::{self, HeaderValue}; use ipc_channel::ipc::{self, IpcSender}; use log::warn; @@ -290,24 +290,39 @@ impl FileManager { response: &mut Response, ) -> Result<(), BlobURLStoreError> { let file_impl = self.store.get_impl(id, file_token, origin_in)?; + /* + Only Fetch Blob Range Request would have unresolved range, and only in that case we care about range header. + */ + let mut is_range_requested = false; match file_impl { FileImpl::Memory(buf) => { let bounds = match bounds { - BlobBounds::Unresolved(range) => get_range_request_bounds(range, buf.size), + BlobBounds::Unresolved(range) => { + if range.is_some() { + is_range_requested = true; + } + get_range_request_bounds(range, buf.size) + }, BlobBounds::Resolved(bounds) => bounds, }; let range = bounds .get_final(Some(buf.size)) .map_err(|_| BlobURLStoreError::InvalidRange)?; - let range = range.to_abs_range(buf.size as usize); + let range = range.to_abs_blob_range(buf.size as usize); let len = range.len() as u64; + let content_range = if is_range_requested { + ContentRange::bytes(range.start as u64..range.end as u64, buf.size).ok() + } else { + None + }; set_headers( &mut response.headers, len, buf.type_string.parse().unwrap_or(mime::TEXT_PLAIN), /* filename */ None, + content_range, ); let mut bytes = vec![]; @@ -327,9 +342,14 @@ impl FileManager { let file = File::open(&metadata.path) .map_err(|e| BlobURLStoreError::External(e.to_string()))?; - + let mut is_range_requested = false; let bounds = match bounds { - BlobBounds::Unresolved(range) => get_range_request_bounds(range, metadata.size), + BlobBounds::Unresolved(range) => { + if range.is_some() { + is_range_requested = true; + } + get_range_request_bounds(range, metadata.size) + }, BlobBounds::Resolved(bounds) => bounds, }; let range = bounds @@ -349,6 +369,13 @@ impl FileManager { .and_then(|osstr| osstr.to_str()) .map(|s| s.to_string()); + let content_range = if is_range_requested { + let abs_range = range.to_abs_blob_range(metadata.size as usize); + ContentRange::bytes(abs_range.start as u64..abs_range.end as u64, metadata.size) + .ok() + } else { + None + }; set_headers( &mut response.headers, metadata.size, @@ -356,6 +383,7 @@ impl FileManager { .first() .unwrap_or(mime::TEXT_PLAIN), filename, + content_range, ); self.fetch_file_in_chunks( @@ -939,8 +967,17 @@ fn read_file_in_chunks( } } -fn set_headers(headers: &mut HeaderMap, content_length: u64, mime: Mime, filename: Option<String>) { +fn set_headers( + headers: &mut HeaderMap, + content_length: u64, + mime: Mime, + filename: Option<String>, + content_range: Option<ContentRange>, +) { headers.typed_insert(ContentLength(content_length)); + if let Some(content_range) = content_range { + headers.typed_insert(content_range); + } headers.typed_insert(ContentType::from(mime.clone())); let name = match filename { Some(name) => name, diff --git a/components/shared/net/filemanager_thread.rs b/components/shared/net/filemanager_thread.rs index c6d0dde7ecb..5167ab1b4de 100644 --- a/components/shared/net/filemanager_thread.rs +++ b/components/shared/net/filemanager_thread.rs @@ -109,6 +109,16 @@ impl RelativePos { end: (start + span).to_usize().unwrap(), } } + + // Per <https://fetch.spec.whatwg.org/#concept-scheme-fetch> step 3.blob.14.8: + // "A range header denotes an inclusive byte range, while the slice blob algorithm input range does not. + // To use the slice blob algorithm, we have to increment rangeEnd." + pub fn to_abs_blob_range(&self, size: usize) -> Range<usize> { + let orig_range = self.to_abs_range(size); + let start = orig_range.start; + let end = usize::min(orig_range.end + 1, size); + Range { start, end } + } } /// Response to file selection request diff --git a/tests/wpt/meta/fetch/range/blob.any.js.ini b/tests/wpt/meta/fetch/range/blob.any.js.ini index b20ec230d9d..9dd565dc64f 100644 --- a/tests/wpt/meta/fetch/range/blob.any.js.ini +++ b/tests/wpt/meta/fetch/range/blob.any.js.ini @@ -1,18 +1,18 @@ [blob.any.html] [A simple blob range request.] - expected: FAIL + expected: PASS [A blob range request with no end.] - expected: FAIL + expected: PASS [A blob range request with no start.] - expected: FAIL + expected: PASS [A simple blob range request with whitespace.] - expected: FAIL + expected: PASS [Blob content with short content and a large range end] - expected: FAIL + expected: PASS [Blob range with whitespace before and after hyphen] expected: FAIL @@ -60,7 +60,7 @@ expected: FAIL [Blob content with short content and a range end matching content length] - expected: FAIL + expected: PASS [Blob range with no value] expected: FAIL @@ -83,19 +83,19 @@ [blob.any.worker.html] [A simple blob range request.] - expected: FAIL + expected: PASS [A blob range request with no end.] - expected: FAIL + expected: PASS [A blob range request with no start.] - expected: FAIL + expected: PASS [A simple blob range request with whitespace.] - expected: FAIL + expected: PASS [Blob content with short content and a large range end] - expected: FAIL + expected: PASS [Blob range with whitespace before and after hyphen] expected: FAIL @@ -143,7 +143,7 @@ expected: FAIL [Blob content with short content and a range end matching content length] - expected: FAIL + expected: PASS [Blob range with no value] expected: FAIL diff --git a/tests/wpt/meta/xhr/blob-range.any.js.ini b/tests/wpt/meta/xhr/blob-range.any.js.ini index e743d94658e..158301c7929 100644 --- a/tests/wpt/meta/xhr/blob-range.any.js.ini +++ b/tests/wpt/meta/xhr/blob-range.any.js.ini @@ -1,24 +1,24 @@ [blob-range.any.worker.html] [A simple blob range request.] - expected: FAIL + expected: PASS [A blob range request with no type.] expected: FAIL [A blob range request with no end.] - expected: FAIL + expected: PASS [A blob range request with no start.] - expected: FAIL + expected: PASS [A simple blob range request with whitespace.] expected: FAIL [Blob content with short content and a large range end] - expected: FAIL + expected: PASS [Blob content with short content and a range end matching content length] - expected: FAIL + expected: PASS [Blob range with whitespace before and after hyphen] expected: FAIL @@ -83,25 +83,25 @@ [blob-range.any.html] [A simple blob range request.] - expected: FAIL + expected: PASS [A blob range request with no type.] expected: FAIL [A blob range request with no end.] - expected: FAIL + expected: PASS [A blob range request with no start.] - expected: FAIL + expected: PASS [A simple blob range request with whitespace.] expected: FAIL [Blob content with short content and a large range end] - expected: FAIL + expected: PASS [Blob content with short content and a range end matching content length] - expected: FAIL + expected: PASS [Blob range with whitespace before and after hyphen] expected: FAIL diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json index 0e36ca7dca4..2577bfabe3e 100644 --- a/tests/wpt/mozilla/meta/MANIFEST.json +++ b/tests/wpt/mozilla/meta/MANIFEST.json @@ -13905,13 +13905,6 @@ {} ] ], - "range_request_blob_url.html": [ - "075397620e989dafc814c0ed2bca46bd476bccf6", - [ - null, - {} - ] - ], "range_request_file_url.html": [ "4fd4ddc8b1a9959e90b243795267c220d6a05f5e", [ diff --git a/tests/wpt/mozilla/tests/mozilla/range_request_blob_url.html b/tests/wpt/mozilla/tests/mozilla/range_request_blob_url.html deleted file mode 100644 index 075397620e9..00000000000 --- a/tests/wpt/mozilla/tests/mozilla/range_request_blob_url.html +++ /dev/null @@ -1,60 +0,0 @@ -<html> -<head> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script> -[{ - range: "bytes=0-", - status: 206, - expected: "abcdefghijklmnopqrstuvwxyz" -}, { - range: "bytes=0-9", - status: 206, - expected: "abcdefghi" -}, { - range: "bytes=1-9", - status: 206, - expected: "bcdefghi" -}, { - range: "bytes=-10", - status: 206, - expected: "qrstuvwxyz" -}, { - range: "bytes=0-100", - status: 206, - expected: "abcdefghijklmnopqrstuvwxyz" -}, { - range: "bytes=100-", - status: 416, - expected: "" -}, { - range: "bytes=-100", - status: 206, - expected: "abcdefghijklmnopqrstuvwxyz" -}].forEach(test => { - promise_test(function() { - const abc = "abcdefghijklmnopqrstuvwxyz"; - const blob = new Blob([abc], { "type": "text/plain" }); - return fetch(URL.createObjectURL(blob), { - headers: { - "Range": test.range - } - }) - .then(response => { - assert_equals(response.status, test.status); - if (response.status != 206) { - return ""; - } - return response.text(); - }) - .then(response => { - assert_equals(response, test.expected); - }); - }); -}); - -</script> -</head> -</body> -</html> - |