Skip to content

Commit

Permalink
[shared storage] Enable E2E getter/setter methods
Browse files Browse the repository at this point in the history
Implement (i.e. hook up to the database) the getter/setter methods on
blink::mojom::SharedStorageDocumentService and on
shared_storage_worklet::mojom::SharedStorageWorkletServiceClient.

Add the SharedStorageKey{Value}Argument <-> WTF::String typemap.

Bug: 1218540
Change-Id: I552df0b2a7447e04d093f37c3a4160cc438f4753
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3570081
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: David Bokan <bokan@chromium.org>
Reviewed-by: Cammie Smith Barnes <cammie@chromium.org>
Commit-Queue: Yao Xiao <yaoxia@chromium.org>
Cr-Commit-Position: refs/heads/main@{#990239}
  • Loading branch information
yaoxiachromium authored and Chromium LUCI CQ committed Apr 8, 2022
1 parent 797b07e commit 7f5bdcd
Show file tree
Hide file tree
Showing 14 changed files with 675 additions and 36 deletions.
282 changes: 282 additions & 0 deletions content/browser/shared_storage/shared_storage_browsertest.cc
Expand Up @@ -24,6 +24,7 @@
#include "content/test/content_browser_test_utils_internal.h"
#include "content/test/fenced_frame_test_utils.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/request_handler_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/features.h"
Expand All @@ -40,6 +41,7 @@ net::Error InvalidUrnError() {
return blink::features::IsFencedFramesShadowDOMBased() ? net::ERR_ABORTED
: net::ERR_INVALID_URL;
}

} // namespace

class TestSharedStorageWorkletHost : public SharedStorageWorkletHost {
Expand Down Expand Up @@ -308,6 +310,37 @@ class SharedStorageBrowserTest : public ContentBrowserTest {
return metadata_1st_retrieval;
}

void ExecuteScriptInWorklet(const ToRenderFrameHost& execution_target,
const std::string& script) {
base::StringPairs run_function_body_replacement;
run_function_body_replacement.push_back(
std::make_pair("{{RUN_FUNCTION_BODY}}", script));

std::string host =
execution_target.render_frame_host()->GetLastCommittedOrigin().host();

GURL module_script_url = https_server()->GetURL(
host, net::test_server::GetFilePathWithReplacements(
"/shared_storage/customizable_module.js",
run_function_body_replacement));

EXPECT_TRUE(ExecJs(
execution_target,
JsReplace("sharedStorage.worklet.addModule($1)", module_script_url)));

EXPECT_EQ(1u, test_worklet_host_manager().GetAttachedWorkletHostsCount());
EXPECT_EQ(0u, test_worklet_host_manager().GetKeepAliveWorkletHostsCount());

EXPECT_TRUE(ExecJs(execution_target, R"(
sharedStorage.runOperation('test-operation');
)"));

// There are 2 "worklet operations": addModule and runOperation.
test_worklet_host_manager()
.GetAttachedWorkletHost()
->WaitForWorkletResponsesCount(2);
}

net::EmbeddedTestServer* https_server() { return &https_server_; }

TestSharedStorageWorkletHostManager& test_worklet_host_manager() {
Expand Down Expand Up @@ -1525,4 +1558,253 @@ IN_PROC_BROWSER_TEST_F(SharedStorageBrowserTest,
EXPECT_DOUBLE_EQ(metadata->budget_to_charge, std::log2(3));
}

IN_PROC_BROWSER_TEST_F(SharedStorageBrowserTest, SetAppendOperationInDocument) {
EXPECT_TRUE(NavigateToURL(shell(),
https_server()->GetURL("a.test", kSimplePagePath)));

EXPECT_TRUE(ExecJs(shell(), R"(
sharedStorage.set('key0', 'value0');
sharedStorage.set('key1', 'value1');
sharedStorage.set('key1', 'value111');
sharedStorage.set('key2', 'value2');
sharedStorage.set('key2', 'value222', {ignoreIfPresent: true});
sharedStorage.set('key3', 'value3');
sharedStorage.append('key3', 'value333');
)"));

WebContentsConsoleObserver console_observer(shell()->web_contents());

ExecuteScriptInWorklet(shell(), R"(
console.log(await sharedStorage.get('key0'));
console.log(await sharedStorage.get('key1'));
console.log(await sharedStorage.get('key2'));
console.log(await sharedStorage.get('key3'));
console.log(await sharedStorage.length());
)");

EXPECT_EQ(5u, console_observer.messages().size());
EXPECT_EQ("value0",
base::UTF16ToUTF8(console_observer.messages()[0].message));
EXPECT_EQ("value111",
base::UTF16ToUTF8(console_observer.messages()[1].message));
EXPECT_EQ("value2",
base::UTF16ToUTF8(console_observer.messages()[2].message));
EXPECT_EQ("value3value333",
base::UTF16ToUTF8(console_observer.messages()[3].message));
EXPECT_EQ("4", base::UTF16ToUTF8(console_observer.messages()[4].message));
}

IN_PROC_BROWSER_TEST_F(SharedStorageBrowserTest, DeleteOperationInDocument) {
EXPECT_TRUE(NavigateToURL(shell(),
https_server()->GetURL("a.test", kSimplePagePath)));

EXPECT_TRUE(ExecJs(shell(), R"(
sharedStorage.set('key0', 'value0');
sharedStorage.delete('key0');
)"));

WebContentsConsoleObserver console_observer(shell()->web_contents());

ExecuteScriptInWorklet(shell(), R"(
console.log(await sharedStorage.length());
console.log(await sharedStorage.get('key0'));
// This won't be executed due to the error in the last get().
console.log(await sharedStorage.length());
)");

EXPECT_EQ(2u, console_observer.messages().size());
EXPECT_EQ("0", base::UTF16ToUTF8(console_observer.messages()[0].message));
EXPECT_EQ(blink::mojom::ConsoleMessageLevel::kInfo,
console_observer.messages()[0].log_level);
EXPECT_EQ("sharedStorage.get() failed",
base::UTF16ToUTF8(console_observer.messages()[1].message));
EXPECT_EQ(blink::mojom::ConsoleMessageLevel::kError,
console_observer.messages()[1].log_level);
}

IN_PROC_BROWSER_TEST_F(SharedStorageBrowserTest, ClearOperationInDocument) {
EXPECT_TRUE(NavigateToURL(shell(),
https_server()->GetURL("a.test", kSimplePagePath)));

EXPECT_TRUE(ExecJs(shell(), R"(
sharedStorage.set('key0', 'value0');
sharedStorage.clear();
)"));

WebContentsConsoleObserver console_observer(shell()->web_contents());

ExecuteScriptInWorklet(shell(), R"(
console.log(await sharedStorage.length());
)");

EXPECT_EQ(1u, console_observer.messages().size());
EXPECT_EQ("0", base::UTF16ToUTF8(console_observer.messages()[0].message));
}

IN_PROC_BROWSER_TEST_F(SharedStorageBrowserTest, SetAppendOperationInWorklet) {
EXPECT_TRUE(NavigateToURL(shell(),
https_server()->GetURL("a.test", kSimplePagePath)));

WebContentsConsoleObserver console_observer(shell()->web_contents());

ExecuteScriptInWorklet(shell(), R"(
sharedStorage.set('key0', 'value0');
sharedStorage.set('key1', 'value1');
sharedStorage.set('key1', 'value111');
sharedStorage.set('key2', 'value2');
sharedStorage.set('key2', 'value222', {ignoreIfPresent: true});
sharedStorage.set('key3', 'value3');
sharedStorage.append('key3', 'value333');
console.log(await sharedStorage.get('key0'));
console.log(await sharedStorage.get('key1'));
console.log(await sharedStorage.get('key2'));
console.log(await sharedStorage.get('key3'));
console.log(await sharedStorage.length());
)");

EXPECT_EQ(5u, console_observer.messages().size());
EXPECT_EQ("value0",
base::UTF16ToUTF8(console_observer.messages()[0].message));
EXPECT_EQ("value111",
base::UTF16ToUTF8(console_observer.messages()[1].message));
EXPECT_EQ("value2",
base::UTF16ToUTF8(console_observer.messages()[2].message));
EXPECT_EQ("value3value333",
base::UTF16ToUTF8(console_observer.messages()[3].message));
EXPECT_EQ("4", base::UTF16ToUTF8(console_observer.messages()[4].message));
}

IN_PROC_BROWSER_TEST_F(SharedStorageBrowserTest,
AppendOperationFailedInWorklet) {
EXPECT_TRUE(NavigateToURL(shell(),
https_server()->GetURL("a.test", kSimplePagePath)));

WebContentsConsoleObserver console_observer(shell()->web_contents());

ExecuteScriptInWorklet(shell(), R"(
await sharedStorage.set('key0', 'a'.repeat(1024));
// This will fail due to the would-be length being too big.
await sharedStorage.append('key0', 'a');
)");

EXPECT_EQ(1u, console_observer.messages().size());
EXPECT_EQ("sharedStorage.append() failed",
base::UTF16ToUTF8(console_observer.messages()[0].message));
EXPECT_EQ(blink::mojom::ConsoleMessageLevel::kError,
console_observer.messages()[0].log_level);
}

IN_PROC_BROWSER_TEST_F(SharedStorageBrowserTest, DeleteOperationInWorklet) {
EXPECT_TRUE(NavigateToURL(shell(),
https_server()->GetURL("a.test", kSimplePagePath)));

WebContentsConsoleObserver console_observer(shell()->web_contents());

ExecuteScriptInWorklet(shell(), R"(
sharedStorage.set('key0', 'value0');
console.log(await sharedStorage.length());
console.log(await sharedStorage.get('key0'));
sharedStorage.delete('key0');
console.log(await sharedStorage.length());
console.log(await sharedStorage.get('key0'));
// This won't be executed due to the error in the last get().
console.log(await sharedStorage.length());
)");

EXPECT_EQ(4u, console_observer.messages().size());
EXPECT_EQ("1", base::UTF16ToUTF8(console_observer.messages()[0].message));
EXPECT_EQ("value0",
base::UTF16ToUTF8(console_observer.messages()[1].message));
EXPECT_EQ("0", base::UTF16ToUTF8(console_observer.messages()[2].message));
EXPECT_EQ("sharedStorage.get() failed",
base::UTF16ToUTF8(console_observer.messages()[3].message));
EXPECT_EQ(blink::mojom::ConsoleMessageLevel::kInfo,
console_observer.messages()[0].log_level);
EXPECT_EQ(blink::mojom::ConsoleMessageLevel::kInfo,
console_observer.messages()[1].log_level);
EXPECT_EQ(blink::mojom::ConsoleMessageLevel::kInfo,
console_observer.messages()[2].log_level);
EXPECT_EQ(blink::mojom::ConsoleMessageLevel::kError,
console_observer.messages()[3].log_level);
}

IN_PROC_BROWSER_TEST_F(SharedStorageBrowserTest, ClearOperationInWorklet) {
EXPECT_TRUE(NavigateToURL(shell(),
https_server()->GetURL("a.test", kSimplePagePath)));

WebContentsConsoleObserver console_observer(shell()->web_contents());

ExecuteScriptInWorklet(shell(), R"(
sharedStorage.set('key0', 'value0');
console.log(await sharedStorage.length());
console.log(await sharedStorage.get('key0'));
sharedStorage.clear();
console.log(await sharedStorage.length());
)");

EXPECT_EQ(3u, console_observer.messages().size());
EXPECT_EQ("1", base::UTF16ToUTF8(console_observer.messages()[0].message));
EXPECT_EQ("value0",
base::UTF16ToUTF8(console_observer.messages()[1].message));
EXPECT_EQ("0", base::UTF16ToUTF8(console_observer.messages()[2].message));
}

IN_PROC_BROWSER_TEST_F(SharedStorageBrowserTest,
AccessStorageInSameOriginDocument) {
EXPECT_TRUE(NavigateToURL(shell(),
https_server()->GetURL("a.test", kSimplePagePath)));

EXPECT_TRUE(ExecJs(shell(), R"(
sharedStorage.set('key0', 'value0');
)"));

EXPECT_TRUE(
NavigateToURL(shell(), https_server()->GetURL("a.test", "/title1.html")));

WebContentsConsoleObserver console_observer(shell()->web_contents());

ExecuteScriptInWorklet(shell(), R"(
console.log(await sharedStorage.length());
)");

EXPECT_EQ(1u, console_observer.messages().size());
EXPECT_EQ("1", base::UTF16ToUTF8(console_observer.messages()[0].message));
}

IN_PROC_BROWSER_TEST_F(SharedStorageBrowserTest,
AccessStorageInDifferentOriginDocument) {
EXPECT_TRUE(NavigateToURL(shell(),
https_server()->GetURL("a.test", kSimplePagePath)));

EXPECT_TRUE(ExecJs(shell(), R"(
sharedStorage.set('key0', 'value0');
)"));

EXPECT_TRUE(
NavigateToURL(shell(), https_server()->GetURL("b.test", "/title1.html")));

WebContentsConsoleObserver console_observer(shell()->web_contents());

ExecuteScriptInWorklet(shell(), R"(
console.log(await sharedStorage.length());
)");

EXPECT_EQ(1u, console_observer.messages().size());
EXPECT_EQ("0", base::UTF16ToUTF8(console_observer.messages()[0].message));
}

} // namespace content
Expand Up @@ -4,6 +4,8 @@

#include "content/browser/shared_storage/shared_storage_document_service_impl.h"

#include "components/services/storage/shared_storage/shared_storage_database.h"
#include "components/services/storage/shared_storage/shared_storage_manager.h"
#include "content/browser/shared_storage/shared_storage_worklet_host.h"
#include "content/browser/shared_storage/shared_storage_worklet_host_manager.h"
#include "content/browser/storage_partition_impl.h"
Expand Down Expand Up @@ -76,6 +78,38 @@ void SharedStorageDocumentServiceImpl::RunURLSelectionOperationOnWorklet(
name, urls, serialized_data, std::move(callback));
}

void SharedStorageDocumentServiceImpl::SharedStorageSet(
const std::u16string& key,
const std::u16string& value,
bool ignore_if_present) {
storage::SharedStorageDatabase::SetBehavior set_behavior =
ignore_if_present
? storage::SharedStorageDatabase::SetBehavior::kIgnoreIfPresent
: storage::SharedStorageDatabase::SetBehavior::kDefault;

GetSharedStorageManager()->Set(render_frame_host().GetLastCommittedOrigin(),
key, value, base::DoNothing(), set_behavior);
}

void SharedStorageDocumentServiceImpl::SharedStorageAppend(
const std::u16string& key,
const std::u16string& value) {
GetSharedStorageManager()->Append(
render_frame_host().GetLastCommittedOrigin(), key, value,
base::DoNothing());
}

void SharedStorageDocumentServiceImpl::SharedStorageDelete(
const std::u16string& key) {
GetSharedStorageManager()->Delete(
render_frame_host().GetLastCommittedOrigin(), key, base::DoNothing());
}

void SharedStorageDocumentServiceImpl::SharedStorageClear() {
GetSharedStorageManager()->Clear(render_frame_host().GetLastCommittedOrigin(),
base::DoNothing());
}

base::WeakPtr<SharedStorageDocumentServiceImpl>
SharedStorageDocumentServiceImpl::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
Expand All @@ -93,6 +127,21 @@ SharedStorageDocumentServiceImpl::GetSharedStorageWorkletHost() {
->GetOrCreateSharedStorageWorkletHost(this);
}

storage::SharedStorageManager*
SharedStorageDocumentServiceImpl::GetSharedStorageManager() {
storage::SharedStorageManager* shared_storage_manager =
static_cast<StoragePartitionImpl*>(
render_frame_host().GetProcess()->GetStoragePartition())
->GetSharedStorageManager();

// This `SharedStorageDocumentServiceImpl` is created only if
// `kSharedStorageAPI` is enabled, in which case the `shared_storage_manager`
// must be valid.
DCHECK(shared_storage_manager);

return shared_storage_manager;
}

DOCUMENT_USER_DATA_KEY_IMPL(SharedStorageDocumentServiceImpl);

} // namespace content

0 comments on commit 7f5bdcd

Please sign in to comment.