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