net_traits/
filemanager_thread.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::cmp::{max, min};
6use std::ops::Range;
7
8use embedder_traits::{EmbedderControlId, EmbedderControlResponse, FilePickerRequest};
9use ipc_channel::ipc::IpcSender;
10use malloc_size_of_derive::MallocSizeOf;
11use num_traits::ToPrimitive;
12use serde::{Deserialize, Serialize};
13use uuid::Uuid;
14
15use crate::blob_url_store::{BlobBuf, BlobURLStoreError};
16
17// HACK: Not really process-safe now, we should send Origin
18//       directly instead of this in future, blocked on #11722
19/// File manager store entry's origin
20pub type FileOrigin = String;
21
22/// A token modulating access to a file for a blob URL.
23#[derive(Clone)]
24pub enum FileTokenCheck {
25    /// Checking against a token not required,
26    /// used for accessing a file
27    /// that isn't linked to from a blob URL.
28    NotRequired,
29    /// Checking against token required.
30    Required(Uuid),
31    /// Request should always fail,
32    /// used for cases when a check is required,
33    /// but no token could be acquired.
34    ShouldFail,
35}
36
37/// Relative slice positions of a sequence,
38/// whose semantic should be consistent with (start, end) parameters in
39/// <https://w3c.github.io/FileAPI/#dfn-slice>
40#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, Serialize)]
41pub struct RelativePos {
42    /// Relative to first byte if non-negative,
43    /// relative to one past last byte if negative,
44    pub start: i64,
45    /// Relative offset from first byte if Some(non-negative),
46    /// relative to one past last byte if Some(negative),
47    /// None if one past last byte
48    pub end: Option<i64>,
49}
50
51impl RelativePos {
52    /// Full range from start to end
53    pub fn full_range() -> RelativePos {
54        RelativePos {
55            start: 0,
56            end: None,
57        }
58    }
59
60    /// Instantiate optional slice position parameters
61    pub fn from_opts(start: Option<i64>, end: Option<i64>) -> RelativePos {
62        RelativePos {
63            start: start.unwrap_or(0),
64            end,
65        }
66    }
67
68    /// Slice the inner sliced range by repositioning
69    pub fn slice_inner(&self, rel_pos: &RelativePos) -> RelativePos {
70        RelativePos {
71            start: self.start + rel_pos.start,
72            end: match (self.end, rel_pos.end) {
73                (Some(old_end), Some(rel_end)) => Some(old_end + rel_end),
74                (old, None) => old,
75                (None, rel) => rel,
76            },
77        }
78    }
79
80    /// Compute absolute range by giving the total size
81    /// <https://w3c.github.io/FileAPI/#slice-method-algo>
82    pub fn to_abs_range(&self, size: usize) -> Range<usize> {
83        let size = size as i64;
84
85        let start = {
86            if self.start < 0 {
87                max(size + self.start, 0)
88            } else {
89                min(self.start, size)
90            }
91        };
92
93        let end = match self.end {
94            Some(rel_end) => {
95                if rel_end < 0 {
96                    max(size + rel_end, 0)
97                } else {
98                    min(rel_end, size)
99                }
100            },
101            None => size,
102        };
103
104        let span: i64 = max(end - start, 0);
105
106        Range {
107            start: start.to_usize().unwrap(),
108            end: (start + span).to_usize().unwrap(),
109        }
110    }
111
112    // Per <https://fetch.spec.whatwg.org/#concept-scheme-fetch> step 3.blob.14.8:
113    // "A range header denotes an inclusive byte range, while the slice blob algorithm input range does not.
114    // To use the slice blob algorithm, we have to increment rangeEnd."
115    pub fn to_abs_blob_range(&self, size: usize) -> Range<usize> {
116        let orig_range = self.to_abs_range(size);
117        let start = orig_range.start;
118        let end = usize::min(orig_range.end + 1, size);
119        Range { start, end }
120    }
121}
122
123#[derive(Debug, Deserialize, Serialize)]
124pub enum FileManagerThreadMsg {
125    /// Select a file or files.
126    SelectFiles(
127        EmbedderControlId,
128        FilePickerRequest,
129        IpcSender<EmbedderControlResponse>,
130    ),
131
132    /// Read FileID-indexed file in chunks, optionally check URL validity based on boolean flag
133    ReadFile(
134        IpcSender<FileManagerResult<ReadFileProgress>>,
135        Uuid,
136        FileOrigin,
137    ),
138
139    /// Add an entry as promoted memory-based blob
140    PromoteMemory(Uuid, BlobBuf, bool, FileOrigin),
141
142    /// Add a sliced entry pointing to the parent FileID, and send back the associated FileID
143    /// as part of a valid Blob URL
144    AddSlicedURLEntry(
145        Uuid,
146        RelativePos,
147        IpcSender<Result<Uuid, BlobURLStoreError>>,
148        FileOrigin,
149    ),
150
151    /// Decrease reference count and send back the acknowledgement
152    DecRef(Uuid, FileOrigin, IpcSender<Result<(), BlobURLStoreError>>),
153
154    /// Activate an internal FileID so it becomes valid as part of a Blob URL
155    ActivateBlobURL(Uuid, IpcSender<Result<(), BlobURLStoreError>>, FileOrigin),
156
157    /// Revoke Blob URL and send back the acknowledgement
158    RevokeBlobURL(Uuid, FileOrigin, IpcSender<Result<(), BlobURLStoreError>>),
159}
160
161#[derive(Debug, Deserialize, Serialize)]
162pub enum ReadFileProgress {
163    Meta(BlobBuf),
164    Partial(Vec<u8>),
165    EOF,
166}
167
168pub type FileManagerResult<T> = Result<T, FileManagerThreadError>;
169
170#[derive(Debug, Deserialize, Serialize)]
171pub enum FileManagerThreadError {
172    /// The selection action is invalid due to exceptional reason
173    InvalidSelection,
174    /// The selection action is cancelled by user
175    UserCancelled,
176    /// Errors returned from file system request
177    FileSystemError(String),
178    /// Blob URL Store error
179    BlobURLStoreError(BlobURLStoreError),
180}