1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
/* 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::str::FromStr;

use serde::{Deserialize, Serialize};
use servo_url::ServoUrl;
use url::Url;
use uuid::Uuid;

use crate::filemanager_thread::FileOrigin;

/// Errors returned to Blob URL Store request
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub enum BlobURLStoreError {
    /// Invalid File UUID
    InvalidFileID,
    /// Invalid URL origin
    InvalidOrigin,
    /// Invalid entry content
    InvalidEntry,
    /// Invalid range
    InvalidRange,
    /// External error, from like file system, I/O etc.
    External(String),
}

/// Standalone blob buffer object
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct BlobBuf {
    pub filename: Option<String>,
    /// MIME type string
    pub type_string: String,
    /// Size of content in bytes
    pub size: u64,
    /// Content of blob
    pub bytes: Vec<u8>,
}

/// Parse URL as Blob URL scheme's definition
///
/// <https://w3c.github.io/FileAPI/#DefinitionOfScheme>
pub fn parse_blob_url(url: &ServoUrl) -> Result<(Uuid, FileOrigin), &'static str> {
    let url_inner = Url::parse(url.path()).map_err(|_| "Failed to parse URL path")?;
    let segs = url_inner
        .path_segments()
        .map(|c| c.collect::<Vec<_>>())
        .ok_or("URL has no path segments")?;

    if url.query().is_some() {
        return Err("URL should not contain a query");
    }

    if segs.len() > 1 {
        return Err("URL should not have more than one path segment");
    }

    let id = {
        let id = segs.first().ok_or("URL has no path segments")?;
        Uuid::from_str(id).map_err(|_| "Failed to parse UUID from path segment")?
    };
    Ok((id, get_blob_origin(&ServoUrl::from_url(url_inner))))
}

/// Given an URL, returning the Origin that a Blob created under this
/// URL should have.
///
/// HACK(izgzhen): Not well-specified on spec, and it is a bit a hack
/// both due to ambiguity of spec and that we have to serialization the
/// Origin here.
pub fn get_blob_origin(url: &ServoUrl) -> FileOrigin {
    if url.scheme() == "file" {
        // NOTE: by default this is "null" (Opaque), which is not ideal
        "file://".to_string()
    } else {
        url.origin().ascii_serialization()
    }
}