Преглед изворни кода

LibWeb: Implement an ephemeral Blob URL store

The Blob URL store is intended to be a singleton across all WebContent
instances. But for now, this implements a per-WebContent store, which
only lives as long as the WebContent process itself.
Timothy Flynn пре 2 година
родитељ
комит
b3f82f724d

+ 1 - 0
Userland/Libraries/LibWeb/CMakeLists.txt

@@ -206,6 +206,7 @@ set(SOURCES
     Fetch/Request.cpp
     Fetch/Response.cpp
     FileAPI/Blob.cpp
+    FileAPI/BlobURLStore.cpp
     FileAPI/File.cpp
     FileAPI/FileList.cpp
     FontCache.cpp

+ 92 - 0
Userland/Libraries/LibWeb/FileAPI/BlobURLStore.cpp

@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <AK/StringBuilder.h>
+#include <AK/URL.h>
+#include <LibWeb/Crypto/Crypto.h>
+#include <LibWeb/FileAPI/Blob.h>
+#include <LibWeb/FileAPI/BlobURLStore.h>
+#include <LibWeb/HTML/Origin.h>
+#include <LibWeb/HTML/Scripting/Environments.h>
+
+namespace Web::FileAPI {
+
+BlobURLStore& blob_url_store()
+{
+    static HashMap<String, BlobURLEntry> store;
+    return store;
+}
+
+// https://w3c.github.io/FileAPI/#unicodeBlobURL
+ErrorOr<String> generate_new_blob_url()
+{
+    // 1. Let result be the empty string.
+    StringBuilder result;
+
+    // 2. Append the string "blob:" to result.
+    TRY(result.try_append("blob:"sv));
+
+    // 3. Let settings be the current settings object
+    auto& settings = HTML::current_settings_object();
+
+    // 4. Let origin be settings’s origin.
+    auto origin = settings.origin();
+
+    // 5. Let serialized be the ASCII serialization of origin.
+    auto serialized = origin.serialize();
+
+    // 6. If serialized is "null", set it to an implementation-defined value.
+    if (serialized == "null"sv)
+        serialized = "ladybird"sv;
+
+    // 7. Append serialized to result.
+    TRY(result.try_append(serialized));
+
+    // 8. Append U+0024 SOLIDUS (/) to result.
+    TRY(result.try_append('/'));
+
+    // 9. Generate a UUID [RFC4122] as a string and append it to result.
+    auto uuid = TRY(Crypto::generate_random_uuid());
+    TRY(result.try_append(uuid));
+
+    // 10. Return result.
+    return result.to_string();
+}
+
+// https://w3c.github.io/FileAPI/#add-an-entry
+ErrorOr<String> add_entry_to_blob_url_store(JS::NonnullGCPtr<Blob> object)
+{
+    // 1. Let store be the user agent’s blob URL store.
+    auto& store = blob_url_store();
+
+    // 2. Let url be the result of generating a new blob URL.
+    auto url = TRY(generate_new_blob_url());
+
+    // 3. Let entry be a new blob URL entry consisting of object and the current settings object.
+    BlobURLEntry entry { object, HTML::current_settings_object() };
+
+    // 4. Set store[url] to entry.
+    TRY(store.try_set(url, move(entry)));
+
+    // 5. Return url.
+    return url;
+}
+
+// https://w3c.github.io/FileAPI/#removeTheEntry
+ErrorOr<void> remove_entry_from_blob_url_store(StringView url)
+{
+    // 1. Let store be the user agent’s blob URL store;
+    auto& store = blob_url_store();
+
+    // 2. Let url string be the result of serializing url.
+    auto url_string = TRY(AK::URL { url }.to_string());
+
+    // 3. Remove store[url string].
+    store.remove(url_string);
+    return {};
+}
+
+}

+ 31 - 0
Userland/Libraries/LibWeb/FileAPI/BlobURLStore.h

@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/HashMap.h>
+#include <AK/String.h>
+#include <LibJS/Heap/GCPtr.h>
+#include <LibJS/Heap/Handle.h>
+#include <LibWeb/Forward.h>
+
+namespace Web::FileAPI {
+
+// https://w3c.github.io/FileAPI/#blob-url-entry
+struct BlobURLEntry {
+    JS::Handle<Blob> object; // FIXME: This could also be a MediaSource after we implement MSE.
+    JS::Handle<HTML::EnvironmentSettingsObject> environment;
+};
+
+// https://w3c.github.io/FileAPI/#BlobURLStore
+using BlobURLStore = HashMap<String, BlobURLEntry>;
+
+BlobURLStore& blob_url_store();
+ErrorOr<String> generate_new_blob_url();
+ErrorOr<String> add_entry_to_blob_url_store(JS::NonnullGCPtr<Blob> object);
+ErrorOr<void> remove_entry_from_blob_url_store(StringView url);
+
+}