mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
When slicing a blob that is already sliced we should reference it's
parent's data instead of creating a subview into the sliced blob. This
keeps the blob ancestry chain small and reduces the number of blobs that
we have to resolve.
Testing: Includes a new crashtest
Fixes: https://github.com/servo/servo/issues/36843
[try
run](1484487366
)
---------
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
204 lines
6.3 KiB
Rust
204 lines
6.3 KiB
Rust
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* 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 std::cmp::{max, min};
|
|
use std::ops::Range;
|
|
use std::path::PathBuf;
|
|
use std::time::SystemTime;
|
|
|
|
use base::id::WebViewId;
|
|
use embedder_traits::FilterPattern;
|
|
use ipc_channel::ipc::IpcSender;
|
|
use malloc_size_of_derive::MallocSizeOf;
|
|
use num_traits::ToPrimitive;
|
|
use serde::{Deserialize, Serialize};
|
|
use uuid::Uuid;
|
|
|
|
use crate::blob_url_store::{BlobBuf, BlobURLStoreError};
|
|
|
|
// HACK: Not really process-safe now, we should send Origin
|
|
// directly instead of this in future, blocked on #11722
|
|
/// File manager store entry's origin
|
|
pub type FileOrigin = String;
|
|
|
|
/// A token modulating access to a file for a blob URL.
|
|
pub enum FileTokenCheck {
|
|
/// Checking against a token not required,
|
|
/// used for accessing a file
|
|
/// that isn't linked to from a blob URL.
|
|
NotRequired,
|
|
/// Checking against token required.
|
|
Required(Uuid),
|
|
/// Request should always fail,
|
|
/// used for cases when a check is required,
|
|
/// but no token could be acquired.
|
|
ShouldFail,
|
|
}
|
|
|
|
/// Relative slice positions of a sequence,
|
|
/// whose semantic should be consistent with (start, end) parameters in
|
|
/// <https://w3c.github.io/FileAPI/#dfn-slice>
|
|
#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, Serialize)]
|
|
pub struct RelativePos {
|
|
/// Relative to first byte if non-negative,
|
|
/// relative to one past last byte if negative,
|
|
pub start: i64,
|
|
/// Relative offset from first byte if Some(non-negative),
|
|
/// relative to one past last byte if Some(negative),
|
|
/// None if one past last byte
|
|
pub end: Option<i64>,
|
|
}
|
|
|
|
impl RelativePos {
|
|
/// Full range from start to end
|
|
pub fn full_range() -> RelativePos {
|
|
RelativePos {
|
|
start: 0,
|
|
end: None,
|
|
}
|
|
}
|
|
|
|
/// Instantiate optional slice position parameters
|
|
pub fn from_opts(start: Option<i64>, end: Option<i64>) -> RelativePos {
|
|
RelativePos {
|
|
start: start.unwrap_or(0),
|
|
end,
|
|
}
|
|
}
|
|
|
|
/// Slice the inner sliced range by repositioning
|
|
pub fn slice_inner(&self, rel_pos: &RelativePos) -> RelativePos {
|
|
RelativePos {
|
|
start: self.start + rel_pos.start,
|
|
end: match (self.end, rel_pos.end) {
|
|
(Some(old_end), Some(rel_end)) => Some(old_end + rel_end),
|
|
(old, None) => old,
|
|
(None, rel) => rel,
|
|
},
|
|
}
|
|
}
|
|
|
|
/// Compute absolute range by giving the total size
|
|
/// <https://w3c.github.io/FileAPI/#slice-method-algo>
|
|
pub fn to_abs_range(&self, size: usize) -> Range<usize> {
|
|
let size = size as i64;
|
|
|
|
let start = {
|
|
if self.start < 0 {
|
|
max(size + self.start, 0)
|
|
} else {
|
|
min(self.start, size)
|
|
}
|
|
};
|
|
|
|
let end = match self.end {
|
|
Some(rel_end) => {
|
|
if rel_end < 0 {
|
|
max(size + rel_end, 0)
|
|
} else {
|
|
min(rel_end, size)
|
|
}
|
|
},
|
|
None => size,
|
|
};
|
|
|
|
let span: i64 = max(end - start, 0);
|
|
|
|
Range {
|
|
start: start.to_usize().unwrap(),
|
|
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
|
|
#[derive(Debug, Deserialize, Serialize)]
|
|
pub struct SelectedFile {
|
|
pub id: Uuid,
|
|
pub filename: PathBuf,
|
|
pub modified: SystemTime,
|
|
pub size: u64,
|
|
// https://w3c.github.io/FileAPI/#dfn-type
|
|
pub type_string: String,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, Serialize)]
|
|
pub enum FileManagerThreadMsg {
|
|
/// Select a single file. Last field is pre-selected file path for testing
|
|
SelectFile(
|
|
WebViewId,
|
|
Vec<FilterPattern>,
|
|
IpcSender<FileManagerResult<SelectedFile>>,
|
|
FileOrigin,
|
|
Option<PathBuf>,
|
|
),
|
|
|
|
/// Select multiple files. Last field is pre-selected file paths for testing
|
|
SelectFiles(
|
|
WebViewId,
|
|
Vec<FilterPattern>,
|
|
IpcSender<FileManagerResult<Vec<SelectedFile>>>,
|
|
FileOrigin,
|
|
Option<Vec<PathBuf>>,
|
|
),
|
|
|
|
/// Read FileID-indexed file in chunks, optionally check URL validity based on boolean flag
|
|
ReadFile(
|
|
IpcSender<FileManagerResult<ReadFileProgress>>,
|
|
Uuid,
|
|
FileOrigin,
|
|
),
|
|
|
|
/// Add an entry as promoted memory-based blob
|
|
PromoteMemory(Uuid, BlobBuf, bool, FileOrigin),
|
|
|
|
/// Add a sliced entry pointing to the parent FileID, and send back the associated FileID
|
|
/// as part of a valid Blob URL
|
|
AddSlicedURLEntry(
|
|
Uuid,
|
|
RelativePos,
|
|
IpcSender<Result<Uuid, BlobURLStoreError>>,
|
|
FileOrigin,
|
|
),
|
|
|
|
/// Decrease reference count and send back the acknowledgement
|
|
DecRef(Uuid, FileOrigin, IpcSender<Result<(), BlobURLStoreError>>),
|
|
|
|
/// Activate an internal FileID so it becomes valid as part of a Blob URL
|
|
ActivateBlobURL(Uuid, IpcSender<Result<(), BlobURLStoreError>>, FileOrigin),
|
|
|
|
/// Revoke Blob URL and send back the acknowledgement
|
|
RevokeBlobURL(Uuid, FileOrigin, IpcSender<Result<(), BlobURLStoreError>>),
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, Serialize)]
|
|
pub enum ReadFileProgress {
|
|
Meta(BlobBuf),
|
|
Partial(Vec<u8>),
|
|
EOF,
|
|
}
|
|
|
|
pub type FileManagerResult<T> = Result<T, FileManagerThreadError>;
|
|
|
|
#[derive(Debug, Deserialize, Serialize)]
|
|
pub enum FileManagerThreadError {
|
|
/// The selection action is invalid due to exceptional reason
|
|
InvalidSelection,
|
|
/// The selection action is cancelled by user
|
|
UserCancelled,
|
|
/// Errors returned from file system request
|
|
FileSystemError(String),
|
|
/// Blob URL Store error
|
|
BlobURLStoreError(BlobURLStoreError),
|
|
}
|