Home | History | Annotate | Download | only in fileapi
      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.
      4 
      5 #include "content/browser/fileapi/fileapi_message_filter.h"
      6 
      7 #include <string>
      8 #include <vector>
      9 
     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"
     30 
     31 namespace content {
     32 
     33 namespace {
     34 
     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";
     39 
     40 const char kFakeContentType[] = "fake/type";
     41 
     42 }  // namespace
     43 
     44 class FileAPIMessageFilterTest : public testing::Test {
     45  public:
     46   FileAPIMessageFilterTest()
     47       : io_browser_thread_(BrowserThread::IO, &message_loop_) {
     48   }
     49 
     50  protected:
     51   virtual void SetUp() OVERRIDE {
     52     file_system_context_ =
     53         CreateFileSystemContextForTesting(NULL, base::FilePath());
     54 
     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(
     60               types[i],
     61               fileapi::FileSystemContext::GetPermissionPolicy(types[i]));
     62     }
     63 
     64     stream_context_ = StreamContext::GetFor(&browser_context_);
     65     blob_storage_context_ = ChromeBlobStorageContext::GetFor(&browser_context_);
     66 
     67     filter_ = new FileAPIMessageFilter(
     68         0 /* process_id */,
     69         browser_context_.GetRequestContext(),
     70         file_system_context_.get(),
     71         blob_storage_context_,
     72         stream_context_);
     73 
     74     // Complete initialization.
     75     message_loop_.RunUntilIdle();
     76   }
     77 
     78   base::MessageLoop message_loop_;
     79   TestBrowserThread io_browser_thread_;
     80 
     81   TestBrowserContext browser_context_;
     82   scoped_refptr<fileapi::FileSystemContext> file_system_context_;
     83   StreamContext* stream_context_;
     84   ChromeBlobStorageContext* blob_storage_context_;
     85 
     86   scoped_refptr<FileAPIMessageFilter> filter_;
     87 };
     88 
     89 TEST_F(FileAPIMessageFilterTest, CloseChannelWithInflightRequest) {
     90   scoped_refptr<FileAPIMessageFilter> filter(
     91       new FileAPIMessageFilter(
     92           0 /* process_id */,
     93           browser_context_.GetRequestContext(),
     94           file_system_context_.get(),
     95           ChromeBlobStorageContext::GetFor(&browser_context_),
     96           StreamContext::GetFor(&browser_context_)));
     97   filter->OnChannelConnected(0);
     98 
     99   // Complete initialization.
    100   message_loop_.RunUntilIdle();
    101 
    102   int request_id = 0;
    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));
    106 
    107   // Close the filter while it has inflight request.
    108   filter->OnChannelClosing();
    109 
    110   // This shouldn't cause DCHECK failure.
    111   message_loop_.RunUntilIdle();
    112 }
    113 
    114 TEST_F(FileAPIMessageFilterTest, MultipleFilters) {
    115   scoped_refptr<FileAPIMessageFilter> filter1(
    116       new FileAPIMessageFilter(
    117           0 /* process_id */,
    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(
    124           1 /* process_id */,
    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);
    131 
    132   // Complete initialization.
    133   message_loop_.RunUntilIdle();
    134 
    135   int request_id = 0;
    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));
    139 
    140   // Close the other filter before the request for filter1 is processed.
    141   filter2->OnChannelClosing();
    142 
    143   // This shouldn't cause DCHECK failure.
    144   message_loop_.RunUntilIdle();
    145 }
    146 
    147 TEST_F(FileAPIMessageFilterTest, BuildEmptyStream) {
    148   StreamRegistry* stream_registry = stream_context_->registry();
    149 
    150   const GURL kUrl(kFakeBlobInternalUrlSpec);
    151   const GURL kDifferentUrl("blob:barfoo");
    152 
    153   EXPECT_EQ(NULL, stream_registry->GetStream(kUrl).get());
    154 
    155   StreamHostMsg_StartBuilding start_message(kUrl, kFakeContentType);
    156   EXPECT_TRUE(filter_->OnMessageReceived(start_message));
    157 
    158   const int kBufferSize = 10;
    159   scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize));
    160   int bytes_read = 0;
    161 
    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);
    168   stream = NULL;
    169 
    170   StreamHostMsg_FinishBuilding finish_message(kUrl);
    171   EXPECT_TRUE(filter_->OnMessageReceived(finish_message));
    172 
    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);
    178 
    179   // Run loop to finish transfer.
    180   message_loop_.RunUntilIdle();
    181 
    182   EXPECT_EQ(Stream::STREAM_COMPLETE,
    183             stream->ReadRawData(buffer.get(), kBufferSize, &bytes_read));
    184   EXPECT_EQ(0, bytes_read);
    185 
    186   // Nothing should be returned for a URL we didn't use.
    187   EXPECT_TRUE(stream_registry->GetStream(kDifferentUrl).get() == NULL);
    188 }
    189 
    190 TEST_F(FileAPIMessageFilterTest, BuildNonEmptyStream) {
    191   StreamRegistry* stream_registry = stream_context_->registry();
    192 
    193   const GURL kUrl(kFakeBlobInternalUrlSpec);
    194 
    195   EXPECT_EQ(NULL, stream_registry->GetStream(kUrl).get());
    196 
    197   StreamHostMsg_StartBuilding start_message(kUrl, kFakeContentType);
    198   EXPECT_TRUE(filter_->OnMessageReceived(start_message));
    199 
    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));
    205 
    206   StreamHostMsg_FinishBuilding finish_message(kUrl);
    207   EXPECT_TRUE(filter_->OnMessageReceived(finish_message));
    208 
    209   // Run loop to finish transfer and commit finalize command.
    210   message_loop_.RunUntilIdle();
    211 
    212   scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kFakeData.size()));
    213   int bytes_read = 0;
    214 
    215   scoped_refptr<Stream> stream = stream_registry->GetStream(kUrl);
    216   ASSERT_FALSE(stream.get() == NULL);
    217 
    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));
    222 
    223   EXPECT_EQ(Stream::STREAM_COMPLETE,
    224             stream->ReadRawData(buffer.get(), kFakeData.size(), &bytes_read));
    225   EXPECT_EQ(0, bytes_read);
    226 }
    227 
    228 TEST_F(FileAPIMessageFilterTest, BuildStreamWithSharedMemory) {
    229   StreamRegistry* stream_registry = stream_context_->registry();
    230 
    231   const GURL kUrl(kFakeBlobInternalUrlSpec);
    232 
    233   EXPECT_EQ(NULL, stream_registry->GetStream(kUrl).get());
    234 
    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
    238   // correctly.
    239   filter_->set_peer_pid_for_testing(base::Process::Current().pid());
    240 
    241   StreamHostMsg_StartBuilding start_message(kUrl, kFakeContentType);
    242   EXPECT_TRUE(filter_->OnMessageReceived(start_message));
    243 
    244   const std::string kFakeData = "foobarbaz";
    245 
    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));
    252 
    253   StreamHostMsg_FinishBuilding finish_message(kUrl);
    254   EXPECT_TRUE(filter_->OnMessageReceived(finish_message));
    255 
    256   // Run loop to finish transfer and commit finalize command.
    257   message_loop_.RunUntilIdle();
    258 
    259   scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kFakeData.size()));
    260   int bytes_read = 0;
    261 
    262   scoped_refptr<Stream> stream = stream_registry->GetStream(kUrl);
    263   ASSERT_FALSE(stream.get() == NULL);
    264 
    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));
    269 
    270   EXPECT_EQ(Stream::STREAM_COMPLETE,
    271             stream->ReadRawData(buffer.get(), kFakeData.size(), &bytes_read));
    272   EXPECT_EQ(0, bytes_read);
    273 }
    274 
    275 TEST_F(FileAPIMessageFilterTest, BuildStreamAndCallOnChannelClosing) {
    276   StreamRegistry* stream_registry = stream_context_->registry();
    277 
    278   const GURL kUrl(kFakeBlobInternalUrlSpec);
    279 
    280   StreamHostMsg_StartBuilding start_message(kUrl, kFakeContentType);
    281   EXPECT_TRUE(filter_->OnMessageReceived(start_message));
    282 
    283   ASSERT_FALSE(stream_registry->GetStream(kUrl).get() == NULL);
    284 
    285   filter_->OnChannelClosing();
    286 
    287   ASSERT_EQ(NULL, stream_registry->GetStream(kUrl).get());
    288 }
    289 
    290 TEST_F(FileAPIMessageFilterTest, CloneStream) {
    291   StreamRegistry* stream_registry = stream_context_->registry();
    292 
    293   const GURL kUrl(kFakeBlobInternalUrlSpec);
    294   const GURL kDestUrl(kFakeBlobInternalUrlSpec2);
    295 
    296   StreamHostMsg_StartBuilding start_message(kUrl, kFakeContentType);
    297   EXPECT_TRUE(filter_->OnMessageReceived(start_message));
    298 
    299   StreamHostMsg_Clone clone_message(kDestUrl, kUrl);
    300   EXPECT_TRUE(filter_->OnMessageReceived(clone_message));
    301 
    302   ASSERT_FALSE(stream_registry->GetStream(kUrl).get() == NULL);
    303   ASSERT_FALSE(stream_registry->GetStream(kDestUrl).get() == NULL);
    304 }
    305 
    306 }  // namespace content
    307