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 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 base::MessageLoop message_loop_;
79 TestBrowserThread io_browser_thread_;
81 TestBrowserContext browser_context_;
82 scoped_refptr<fileapi::FileSystemContext> file_system_context_;
83 StreamContext* stream_context_;
84 ChromeBlobStorageContext* blob_storage_context_;
86 scoped_refptr<FileAPIMessageFilter> filter_;
89 TEST_F(FileAPIMessageFilterTest, CloseChannelWithInflightRequest) {
90 scoped_refptr<FileAPIMessageFilter> filter(
91 new FileAPIMessageFilter(
93 browser_context_.GetRequestContext(),
94 file_system_context_.get(),
95 ChromeBlobStorageContext::GetFor(&browser_context_),
96 StreamContext::GetFor(&browser_context_)));
97 filter->OnChannelConnected(0);
99 // Complete initialization.
100 message_loop_.RunUntilIdle();
103 const GURL kUrl("filesystem:http://example.com/temporary/foo");
104 FileSystemHostMsg_ReadMetadata read_metadata(request_id++, kUrl);
105 EXPECT_TRUE(filter->OnMessageReceived(read_metadata));
107 // Close the filter while it has inflight request.
108 filter->OnChannelClosing();
110 // This shouldn't cause DCHECK failure.
111 message_loop_.RunUntilIdle();
114 TEST_F(FileAPIMessageFilterTest, MultipleFilters) {
115 scoped_refptr<FileAPIMessageFilter> filter1(
116 new FileAPIMessageFilter(
118 browser_context_.GetRequestContext(),
119 file_system_context_.get(),
120 ChromeBlobStorageContext::GetFor(&browser_context_),
121 StreamContext::GetFor(&browser_context_)));
122 scoped_refptr<FileAPIMessageFilter> filter2(
123 new FileAPIMessageFilter(
125 browser_context_.GetRequestContext(),
126 file_system_context_.get(),
127 ChromeBlobStorageContext::GetFor(&browser_context_),
128 StreamContext::GetFor(&browser_context_)));
129 filter1->OnChannelConnected(0);
130 filter2->OnChannelConnected(1);
132 // Complete initialization.
133 message_loop_.RunUntilIdle();
136 const GURL kUrl("filesystem:http://example.com/temporary/foo");
137 FileSystemHostMsg_ReadMetadata read_metadata(request_id++, kUrl);
138 EXPECT_TRUE(filter1->OnMessageReceived(read_metadata));
140 // Close the other filter before the request for filter1 is processed.
141 filter2->OnChannelClosing();
143 // This shouldn't cause DCHECK failure.
144 message_loop_.RunUntilIdle();
147 TEST_F(FileAPIMessageFilterTest, BuildEmptyStream) {
148 StreamRegistry* stream_registry = stream_context_->registry();
150 const GURL kUrl(kFakeBlobInternalUrlSpec);
151 const GURL kDifferentUrl("blob:barfoo");
153 EXPECT_EQ(NULL, stream_registry->GetStream(kUrl).get());
155 StreamHostMsg_StartBuilding start_message(kUrl, kFakeContentType);
156 EXPECT_TRUE(filter_->OnMessageReceived(start_message));
158 const int kBufferSize = 10;
159 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize));
162 scoped_refptr<Stream> stream = stream_registry->GetStream(kUrl);
163 // Stream becomes available for read right after registration.
164 ASSERT_FALSE(stream.get() == NULL);
165 EXPECT_EQ(Stream::STREAM_EMPTY,
166 stream->ReadRawData(buffer.get(), kBufferSize, &bytes_read));
167 EXPECT_EQ(0, bytes_read);
170 StreamHostMsg_FinishBuilding finish_message(kUrl);
171 EXPECT_TRUE(filter_->OnMessageReceived(finish_message));
173 stream = stream_registry->GetStream(kUrl);
174 ASSERT_FALSE(stream.get() == NULL);
175 EXPECT_EQ(Stream::STREAM_EMPTY,
176 stream->ReadRawData(buffer.get(), kBufferSize, &bytes_read));
177 EXPECT_EQ(0, bytes_read);
179 // Run loop to finish transfer.
180 message_loop_.RunUntilIdle();
182 EXPECT_EQ(Stream::STREAM_COMPLETE,
183 stream->ReadRawData(buffer.get(), kBufferSize, &bytes_read));
184 EXPECT_EQ(0, bytes_read);
186 // Nothing should be returned for a URL we didn't use.
187 EXPECT_TRUE(stream_registry->GetStream(kDifferentUrl).get() == NULL);
190 TEST_F(FileAPIMessageFilterTest, BuildNonEmptyStream) {
191 StreamRegistry* stream_registry = stream_context_->registry();
193 const GURL kUrl(kFakeBlobInternalUrlSpec);
195 EXPECT_EQ(NULL, stream_registry->GetStream(kUrl).get());
197 StreamHostMsg_StartBuilding start_message(kUrl, kFakeContentType);
198 EXPECT_TRUE(filter_->OnMessageReceived(start_message));
200 webkit_blob::BlobData::Item item;
201 const std::string kFakeData = "foobarbaz";
202 item.SetToBytes(kFakeData.data(), kFakeData.size());
203 StreamHostMsg_AppendBlobDataItem append_message(kUrl, item);
204 EXPECT_TRUE(filter_->OnMessageReceived(append_message));
206 StreamHostMsg_FinishBuilding finish_message(kUrl);
207 EXPECT_TRUE(filter_->OnMessageReceived(finish_message));
209 // Run loop to finish transfer and commit finalize command.
210 message_loop_.RunUntilIdle();
212 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kFakeData.size()));
215 scoped_refptr<Stream> stream = stream_registry->GetStream(kUrl);
216 ASSERT_FALSE(stream.get() == NULL);
218 EXPECT_EQ(Stream::STREAM_HAS_DATA,
219 stream->ReadRawData(buffer.get(), kFakeData.size(), &bytes_read));
220 EXPECT_EQ(kFakeData.size(), static_cast<size_t>(bytes_read));
221 EXPECT_EQ(kFakeData, std::string(buffer->data(), bytes_read));
223 EXPECT_EQ(Stream::STREAM_COMPLETE,
224 stream->ReadRawData(buffer.get(), kFakeData.size(), &bytes_read));
225 EXPECT_EQ(0, bytes_read);
228 TEST_F(FileAPIMessageFilterTest, BuildStreamWithSharedMemory) {
229 StreamRegistry* stream_registry = stream_context_->registry();
231 const GURL kUrl(kFakeBlobInternalUrlSpec);
233 EXPECT_EQ(NULL, stream_registry->GetStream(kUrl).get());
235 // For win, we need to set valid PID to the filter.
236 // OnAppendSharedMemoryToStream passes the peer process's handle to
237 // SharedMemory's constructor. If it's incorrect, DuplicateHandle won't work
239 filter_->set_peer_pid_for_testing(base::Process::Current().pid());
241 StreamHostMsg_StartBuilding start_message(kUrl, kFakeContentType);
242 EXPECT_TRUE(filter_->OnMessageReceived(start_message));
244 const std::string kFakeData = "foobarbaz";
246 scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory);
247 ASSERT_TRUE(shared_memory->CreateAndMapAnonymous(kFakeData.size()));
248 memcpy(shared_memory->memory(), kFakeData.data(), kFakeData.size());
249 StreamHostMsg_SyncAppendSharedMemory append_message(
250 kUrl, shared_memory->handle(), kFakeData.size());
251 EXPECT_TRUE(filter_->OnMessageReceived(append_message));
253 StreamHostMsg_FinishBuilding finish_message(kUrl);
254 EXPECT_TRUE(filter_->OnMessageReceived(finish_message));
256 // Run loop to finish transfer and commit finalize command.
257 message_loop_.RunUntilIdle();
259 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kFakeData.size()));
262 scoped_refptr<Stream> stream = stream_registry->GetStream(kUrl);
263 ASSERT_FALSE(stream.get() == NULL);
265 EXPECT_EQ(Stream::STREAM_HAS_DATA,
266 stream->ReadRawData(buffer.get(), kFakeData.size(), &bytes_read));
267 EXPECT_EQ(kFakeData.size(), static_cast<size_t>(bytes_read));
268 EXPECT_EQ(kFakeData, std::string(buffer->data(), bytes_read));
270 EXPECT_EQ(Stream::STREAM_COMPLETE,
271 stream->ReadRawData(buffer.get(), kFakeData.size(), &bytes_read));
272 EXPECT_EQ(0, bytes_read);
275 TEST_F(FileAPIMessageFilterTest, BuildStreamAndCallOnChannelClosing) {
276 StreamRegistry* stream_registry = stream_context_->registry();
278 const GURL kUrl(kFakeBlobInternalUrlSpec);
280 StreamHostMsg_StartBuilding start_message(kUrl, kFakeContentType);
281 EXPECT_TRUE(filter_->OnMessageReceived(start_message));
283 ASSERT_FALSE(stream_registry->GetStream(kUrl).get() == NULL);
285 filter_->OnChannelClosing();
287 ASSERT_EQ(NULL, stream_registry->GetStream(kUrl).get());
290 TEST_F(FileAPIMessageFilterTest, CloneStream) {
291 StreamRegistry* stream_registry = stream_context_->registry();
293 const GURL kUrl(kFakeBlobInternalUrlSpec);
294 const GURL kDestUrl(kFakeBlobInternalUrlSpec2);
296 StreamHostMsg_StartBuilding start_message(kUrl, kFakeContentType);
297 EXPECT_TRUE(filter_->OnMessageReceived(start_message));
299 StreamHostMsg_Clone clone_message(kDestUrl, kUrl);
300 EXPECT_TRUE(filter_->OnMessageReceived(clone_message));
302 ASSERT_FALSE(stream_registry->GetStream(kUrl).get() == NULL);
303 ASSERT_FALSE(stream_registry->GetStream(kDestUrl).get() == NULL);
306 } // namespace content