1 // Copyright 2013 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.
5 #include "content/browser/fileapi/fileapi_message_filter.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/memory/shared_memory.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/process/process.h"
14 #include "content/browser/child_process_security_policy_impl.h"
15 #include "content/browser/fileapi/chrome_blob_storage_context.h"
16 #include "content/browser/streams/stream_registry.h"
17 #include "content/common/fileapi/file_system_messages.h"
18 #include "content/common/fileapi/webblob_messages.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/common/common_param_traits.h"
21 #include "content/public/test/mock_render_process_host.h"
22 #include "content/public/test/test_browser_context.h"
23 #include "content/public/test/test_browser_thread.h"
24 #include "content/public/test/test_file_system_context.h"
25 #include "net/base/io_buffer.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27 #include "webkit/browser/blob/blob_storage_context.h"
28 #include "webkit/browser/fileapi/file_system_context.h"
29 #include "webkit/common/blob/blob_data.h"
35 const char kFakeBlobInternalUrlSpec[] =
36 "blob:blobinternal%3A///dc83ede4-9bbd-453b-be2e-60fd623fcc93";
37 const char kFakeBlobInternalUrlSpec2[] =
38 "blob:blobinternal%3A///d28ae2e7-d233-4dda-9598-d135fe5d403e";
40 const char kFakeContentType[] = "fake/type";
44 class FileAPIMessageFilterTest : public testing::Test {
46 FileAPIMessageFilterTest()
47 : io_browser_thread_(BrowserThread::IO, &message_loop_) {
51 virtual void SetUp() OVERRIDE {
52 file_system_context_ =
53 fileapi::CreateFileSystemContextForTesting(NULL, base::FilePath());
55 std::vector<fileapi::FileSystemType> types;
56 file_system_context_->GetFileSystemTypes(&types);
57 for (size_t i = 0; i < types.size(); ++i) {
58 ChildProcessSecurityPolicyImpl::GetInstance()->
59 RegisterFileSystemPermissionPolicy(
61 fileapi::FileSystemContext::GetPermissionPolicy(types[i]));
64 stream_context_ = StreamContext::GetFor(&browser_context_);
65 blob_storage_context_ = ChromeBlobStorageContext::GetFor(&browser_context_);
67 filter_ = new FileAPIMessageFilter(
69 browser_context_.GetRequestContext(),
70 file_system_context_.get(),
71 blob_storage_context_,
74 // Complete initialization.
75 message_loop_.RunUntilIdle();
78 // Tests via OnMessageReceived(const IPC::Message&). The channel proxy calls
80 bool InvokeOnMessageReceived(const IPC::Message& message) {
82 return filter_->OnMessageReceived(message, &message_was_ok);
85 base::MessageLoop message_loop_;
86 TestBrowserThread io_browser_thread_;
88 TestBrowserContext browser_context_;
89 scoped_refptr<fileapi::FileSystemContext> file_system_context_;
90 StreamContext* stream_context_;
91 ChromeBlobStorageContext* blob_storage_context_;
93 scoped_refptr<FileAPIMessageFilter> filter_;
96 TEST_F(FileAPIMessageFilterTest, CloseChannelWithInflightRequest) {
97 scoped_refptr<FileAPIMessageFilter> filter(
98 new FileAPIMessageFilter(
100 browser_context_.GetRequestContext(),
101 file_system_context_.get(),
102 ChromeBlobStorageContext::GetFor(&browser_context_),
103 StreamContext::GetFor(&browser_context_)));
104 filter->OnChannelConnected(0);
106 // Complete initialization.
107 message_loop_.RunUntilIdle();
110 const GURL kUrl("filesystem:http://example.com/temporary/foo");
111 FileSystemHostMsg_ReadMetadata read_metadata(request_id++, kUrl);
113 EXPECT_TRUE(filter->OnMessageReceived(read_metadata, &message_was_ok));
115 // Close the filter while it has inflight request.
116 filter->OnChannelClosing();
118 // This shouldn't cause DCHECK failure.
119 message_loop_.RunUntilIdle();
122 TEST_F(FileAPIMessageFilterTest, MultipleFilters) {
123 scoped_refptr<FileAPIMessageFilter> filter1(
124 new FileAPIMessageFilter(
126 browser_context_.GetRequestContext(),
127 file_system_context_.get(),
128 ChromeBlobStorageContext::GetFor(&browser_context_),
129 StreamContext::GetFor(&browser_context_)));
130 scoped_refptr<FileAPIMessageFilter> filter2(
131 new FileAPIMessageFilter(
133 browser_context_.GetRequestContext(),
134 file_system_context_.get(),
135 ChromeBlobStorageContext::GetFor(&browser_context_),
136 StreamContext::GetFor(&browser_context_)));
137 filter1->OnChannelConnected(0);
138 filter2->OnChannelConnected(1);
140 // Complete initialization.
141 message_loop_.RunUntilIdle();
144 const GURL kUrl("filesystem:http://example.com/temporary/foo");
145 FileSystemHostMsg_ReadMetadata read_metadata(request_id++, kUrl);
147 EXPECT_TRUE(filter1->OnMessageReceived(read_metadata, &message_was_ok));
149 // Close the other filter before the request for filter1 is processed.
150 filter2->OnChannelClosing();
152 // This shouldn't cause DCHECK failure.
153 message_loop_.RunUntilIdle();
156 TEST_F(FileAPIMessageFilterTest, BuildEmptyStream) {
157 StreamRegistry* stream_registry = stream_context_->registry();
159 const GURL kUrl(kFakeBlobInternalUrlSpec);
160 const GURL kDifferentUrl("blob:barfoo");
162 EXPECT_EQ(NULL, stream_registry->GetStream(kUrl).get());
164 StreamHostMsg_StartBuilding start_message(kUrl, kFakeContentType);
165 EXPECT_TRUE(InvokeOnMessageReceived(start_message));
167 const int kBufferSize = 10;
168 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize));
171 scoped_refptr<Stream> stream = stream_registry->GetStream(kUrl);
172 // Stream becomes available for read right after registration.
173 ASSERT_FALSE(stream.get() == NULL);
174 EXPECT_EQ(Stream::STREAM_EMPTY,
175 stream->ReadRawData(buffer.get(), kBufferSize, &bytes_read));
176 EXPECT_EQ(0, bytes_read);
179 StreamHostMsg_FinishBuilding finish_message(kUrl);
180 EXPECT_TRUE(InvokeOnMessageReceived(finish_message));
182 stream = stream_registry->GetStream(kUrl);
183 ASSERT_FALSE(stream.get() == NULL);
184 EXPECT_EQ(Stream::STREAM_EMPTY,
185 stream->ReadRawData(buffer.get(), kBufferSize, &bytes_read));
186 EXPECT_EQ(0, bytes_read);
188 // Run loop to finish transfer.
189 message_loop_.RunUntilIdle();
191 EXPECT_EQ(Stream::STREAM_COMPLETE,
192 stream->ReadRawData(buffer.get(), kBufferSize, &bytes_read));
193 EXPECT_EQ(0, bytes_read);
195 // Nothing should be returned for a URL we didn't use.
196 EXPECT_TRUE(stream_registry->GetStream(kDifferentUrl).get() == NULL);
199 TEST_F(FileAPIMessageFilterTest, BuildNonEmptyStream) {
200 StreamRegistry* stream_registry = stream_context_->registry();
202 const GURL kUrl(kFakeBlobInternalUrlSpec);
204 EXPECT_EQ(NULL, stream_registry->GetStream(kUrl).get());
206 StreamHostMsg_StartBuilding start_message(kUrl, kFakeContentType);
207 EXPECT_TRUE(InvokeOnMessageReceived(start_message));
209 webkit_blob::BlobData::Item item;
210 const std::string kFakeData = "foobarbaz";
211 item.SetToBytes(kFakeData.data(), kFakeData.size());
212 StreamHostMsg_AppendBlobDataItem append_message(kUrl, item);
213 EXPECT_TRUE(InvokeOnMessageReceived(append_message));
215 StreamHostMsg_FinishBuilding finish_message(kUrl);
216 EXPECT_TRUE(InvokeOnMessageReceived(finish_message));
218 // Run loop to finish transfer and commit finalize command.
219 message_loop_.RunUntilIdle();
221 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kFakeData.size()));
224 scoped_refptr<Stream> stream = stream_registry->GetStream(kUrl);
225 ASSERT_FALSE(stream.get() == NULL);
227 EXPECT_EQ(Stream::STREAM_HAS_DATA,
228 stream->ReadRawData(buffer.get(), kFakeData.size(), &bytes_read));
229 EXPECT_EQ(kFakeData.size(), static_cast<size_t>(bytes_read));
230 EXPECT_EQ(kFakeData, std::string(buffer->data(), bytes_read));
232 EXPECT_EQ(Stream::STREAM_COMPLETE,
233 stream->ReadRawData(buffer.get(), kFakeData.size(), &bytes_read));
234 EXPECT_EQ(0, bytes_read);
237 TEST_F(FileAPIMessageFilterTest, BuildStreamWithSharedMemory) {
238 StreamRegistry* stream_registry = stream_context_->registry();
240 const GURL kUrl(kFakeBlobInternalUrlSpec);
242 EXPECT_EQ(NULL, stream_registry->GetStream(kUrl).get());
244 // For win, we need to set valid PID to the filter.
245 // OnAppendSharedMemoryToStream passes the peer process's handle to
246 // SharedMemory's constructor. If it's incorrect, DuplicateHandle won't work
248 filter_->set_peer_pid_for_testing(base::Process::Current().pid());
250 StreamHostMsg_StartBuilding start_message(kUrl, kFakeContentType);
251 EXPECT_TRUE(InvokeOnMessageReceived(start_message));
253 const std::string kFakeData = "foobarbaz";
255 scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory);
256 ASSERT_TRUE(shared_memory->CreateAndMapAnonymous(kFakeData.size()));
257 memcpy(shared_memory->memory(), kFakeData.data(), kFakeData.size());
258 StreamHostMsg_SyncAppendSharedMemory append_message(
259 kUrl, shared_memory->handle(), kFakeData.size());
260 EXPECT_TRUE(InvokeOnMessageReceived(append_message));
262 StreamHostMsg_FinishBuilding finish_message(kUrl);
263 EXPECT_TRUE(InvokeOnMessageReceived(finish_message));
265 // Run loop to finish transfer and commit finalize command.
266 message_loop_.RunUntilIdle();
268 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kFakeData.size()));
271 scoped_refptr<Stream> stream = stream_registry->GetStream(kUrl);
272 ASSERT_FALSE(stream.get() == NULL);
274 EXPECT_EQ(Stream::STREAM_HAS_DATA,
275 stream->ReadRawData(buffer.get(), kFakeData.size(), &bytes_read));
276 EXPECT_EQ(kFakeData.size(), static_cast<size_t>(bytes_read));
277 EXPECT_EQ(kFakeData, std::string(buffer->data(), bytes_read));
279 EXPECT_EQ(Stream::STREAM_COMPLETE,
280 stream->ReadRawData(buffer.get(), kFakeData.size(), &bytes_read));
281 EXPECT_EQ(0, bytes_read);
284 TEST_F(FileAPIMessageFilterTest, BuildStreamAndCallOnChannelClosing) {
285 StreamRegistry* stream_registry = stream_context_->registry();
287 const GURL kUrl(kFakeBlobInternalUrlSpec);
289 StreamHostMsg_StartBuilding start_message(kUrl, kFakeContentType);
290 EXPECT_TRUE(InvokeOnMessageReceived(start_message));
292 ASSERT_FALSE(stream_registry->GetStream(kUrl).get() == NULL);
294 filter_->OnChannelClosing();
296 ASSERT_EQ(NULL, stream_registry->GetStream(kUrl).get());
299 TEST_F(FileAPIMessageFilterTest, CloneStream) {
300 StreamRegistry* stream_registry = stream_context_->registry();
302 const GURL kUrl(kFakeBlobInternalUrlSpec);
303 const GURL kDestUrl(kFakeBlobInternalUrlSpec2);
305 StreamHostMsg_StartBuilding start_message(kUrl, kFakeContentType);
306 EXPECT_TRUE(InvokeOnMessageReceived(start_message));
308 StreamHostMsg_Clone clone_message(kDestUrl, kUrl);
309 EXPECT_TRUE(InvokeOnMessageReceived(clone_message));
311 ASSERT_FALSE(stream_registry->GetStream(kUrl).get() == NULL);
312 ASSERT_FALSE(stream_registry->GetStream(kDestUrl).get() == NULL);
315 } // namespace content