1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "third_party/blink/renderer/core/fileapi/public_url_manager.h"
6
7 #include "mojo/public/cpp/bindings/associated_receiver.h"
8 #include "mojo/public/cpp/bindings/pending_remote.h"
9 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11 #include "third_party/blink/public/common/features.h"
12 #include "third_party/blink/renderer/core/fileapi/url_registry.h"
13 #include "third_party/blink/renderer/core/testing/null_execution_context.h"
14 #include "third_party/blink/renderer/platform/blob/testing/fake_blob.h"
15 #include "third_party/blink/renderer/platform/blob/testing/fake_blob_url_store.h"
16 #include "third_party/blink/renderer/platform/heap/persistent.h"
17 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
18 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
19
20 namespace blink {
21 namespace {
22
23 using mojom::blink::BlobURLStore;
24
25 class TestURLRegistrable : public URLRegistrable {
26 public:
TestURLRegistrable(URLRegistry * registry,mojo::PendingRemote<mojom::blink::Blob> blob=mojo::NullRemote ())27 TestURLRegistrable(
28 URLRegistry* registry,
29 mojo::PendingRemote<mojom::blink::Blob> blob = mojo::NullRemote())
30 : registry_(registry), blob_(std::move(blob)) {}
31
Registry() const32 URLRegistry& Registry() const override { return *registry_; }
33
IsMojoBlob()34 bool IsMojoBlob() override { return bool{blob_}; }
35
CloneMojoBlob(mojo::PendingReceiver<mojom::blink::Blob> receiver)36 void CloneMojoBlob(
37 mojo::PendingReceiver<mojom::blink::Blob> receiver) override {
38 if (!blob_)
39 return;
40 blob_->Clone(std::move(receiver));
41 }
42
43 private:
44 URLRegistry* const registry_;
45 mojo::Remote<mojom::blink::Blob> blob_;
46 };
47
48 class FakeURLRegistry : public URLRegistry {
49 public:
RegisterURL(SecurityOrigin * origin,const KURL & url,URLRegistrable * registrable)50 void RegisterURL(SecurityOrigin* origin,
51 const KURL& url,
52 URLRegistrable* registrable) override {
53 registrations.push_back(Registration{origin, url, registrable});
54 }
UnregisterURL(const KURL &)55 void UnregisterURL(const KURL&) override {}
56
57 struct Registration {
58 SecurityOrigin* origin;
59 KURL url;
60 URLRegistrable* registrable;
61 };
62 Vector<Registration> registrations;
63 };
64
65 } // namespace
66
67 class PublicURLManagerTest : public testing::Test {
68 public:
PublicURLManagerTest()69 PublicURLManagerTest() : url_store_receiver_(&url_store_) {}
70
SetUp()71 void SetUp() override {
72 execution_context_ = MakeGarbageCollected<NullExecutionContext>();
73 // By default this creates a unique origin, which is exactly what this test
74 // wants.
75 execution_context_->SetUpSecurityContextForTesting();
76
77 HeapMojoAssociatedRemote<BlobURLStore> url_store_remote(execution_context_);
78 url_store_receiver_.Bind(
79 url_store_remote.BindNewEndpointAndPassDedicatedReceiver());
80 url_manager().SetURLStoreForTesting(std::move(url_store_remote));
81 }
82
url_manager()83 PublicURLManager& url_manager() {
84 return execution_context_->GetPublicURLManager();
85 }
86
CreateMojoBlob(const String & uuid)87 mojo::PendingRemote<mojom::blink::Blob> CreateMojoBlob(const String& uuid) {
88 mojo::PendingRemote<mojom::blink::Blob> result;
89 mojo::MakeSelfOwnedReceiver(std::make_unique<FakeBlob>(uuid),
90 result.InitWithNewPipeAndPassReceiver());
91 return result;
92 }
93
94 protected:
95 Persistent<NullExecutionContext> execution_context_;
96
97 FakeBlobURLStore url_store_;
98 mojo::AssociatedReceiver<BlobURLStore> url_store_receiver_;
99 };
100
TEST_F(PublicURLManagerTest,RegisterNonMojoBlob)101 TEST_F(PublicURLManagerTest, RegisterNonMojoBlob) {
102 FakeURLRegistry registry;
103 TestURLRegistrable registrable(®istry);
104 String url = url_manager().RegisterURL(®istrable);
105 ASSERT_EQ(1u, registry.registrations.size());
106 EXPECT_EQ(0u, url_store_.registrations.size());
107 EXPECT_EQ(execution_context_->GetSecurityOrigin(),
108 registry.registrations[0].origin);
109 EXPECT_EQ(url, registry.registrations[0].url);
110 EXPECT_EQ(®istrable, registry.registrations[0].registrable);
111
112 EXPECT_TRUE(SecurityOrigin::CreateFromString(url)->IsSameOriginWith(
113 execution_context_->GetSecurityOrigin()));
114 EXPECT_EQ(execution_context_->GetSecurityOrigin(),
115 SecurityOrigin::CreateFromString(url));
116
117 url_manager().Revoke(KURL(url));
118 EXPECT_FALSE(SecurityOrigin::CreateFromString(url)->IsSameOriginWith(
119 execution_context_->GetSecurityOrigin()));
120 url_store_receiver_.FlushForTesting();
121 // Even though this was not a mojo blob, the PublicURLManager might not know
122 // that, so still expect a revocation on the mojo interface.
123 ASSERT_EQ(1u, url_store_.revocations.size());
124 EXPECT_EQ(url, url_store_.revocations[0]);
125 }
126
TEST_F(PublicURLManagerTest,RegisterMojoBlob)127 TEST_F(PublicURLManagerTest, RegisterMojoBlob) {
128 FakeURLRegistry registry;
129 TestURLRegistrable registrable(®istry, CreateMojoBlob("id"));
130 String url = url_manager().RegisterURL(®istrable);
131
132 EXPECT_EQ(0u, registry.registrations.size());
133 ASSERT_EQ(1u, url_store_.registrations.size());
134 EXPECT_EQ(url, url_store_.registrations.begin()->key);
135
136 EXPECT_TRUE(SecurityOrigin::CreateFromString(url)->IsSameOriginWith(
137 execution_context_->GetSecurityOrigin()));
138 EXPECT_EQ(execution_context_->GetSecurityOrigin(),
139 SecurityOrigin::CreateFromString(url));
140
141 url_manager().Revoke(KURL(url));
142 EXPECT_FALSE(SecurityOrigin::CreateFromString(url)->IsSameOriginWith(
143 execution_context_->GetSecurityOrigin()));
144 url_store_receiver_.FlushForTesting();
145 ASSERT_EQ(1u, url_store_.revocations.size());
146 EXPECT_EQ(url, url_store_.revocations[0]);
147 }
148
TEST_F(PublicURLManagerTest,RevokeValidNonRegisteredURL)149 TEST_F(PublicURLManagerTest, RevokeValidNonRegisteredURL) {
150 execution_context_->SetURL(KURL("http://example.com/foo/bar"));
151 execution_context_->SetUpSecurityContextForTesting();
152
153 KURL url = KURL("blob:http://example.com/id");
154 url_manager().Revoke(url);
155 url_store_receiver_.FlushForTesting();
156 ASSERT_EQ(1u, url_store_.revocations.size());
157 EXPECT_EQ(url, url_store_.revocations[0]);
158 }
159
TEST_F(PublicURLManagerTest,RevokeInvalidURL)160 TEST_F(PublicURLManagerTest, RevokeInvalidURL) {
161 execution_context_->SetURL(KURL("http://example.com/foo/bar"));
162 execution_context_->SetUpSecurityContextForTesting();
163
164 KURL invalid_scheme_url = KURL("blb:http://example.com/id");
165 KURL fragment_url = KURL("blob:http://example.com/id#fragment");
166 KURL invalid_origin_url = KURL("blob:http://foobar.com/id");
167 url_manager().Revoke(invalid_scheme_url);
168 url_manager().Revoke(fragment_url);
169 url_manager().Revoke(invalid_origin_url);
170 url_store_receiver_.FlushForTesting();
171 // Both should have been silently ignored.
172 EXPECT_TRUE(url_store_.revocations.IsEmpty());
173 }
174
175 } // namespace blink
176