| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 // Copyright 2015 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/blob_storage/blob_dispatcher_host.h" | 
|  | 6 | 
|  | 7 #include <vector> | 
|  | 8 | 
|  | 9 #include "base/command_line.h" | 
|  | 10 #include "base/memory/scoped_ptr.h" | 
|  | 11 #include "base/memory/shared_memory.h" | 
|  | 12 #include "base/run_loop.h" | 
|  | 13 #include "base/tuple.h" | 
|  | 14 #include "content/browser/fileapi/chrome_blob_storage_context.h" | 
|  | 15 #include "content/common/fileapi/webblob_messages.h" | 
|  | 16 #include "content/public/common/content_switches.h" | 
|  | 17 #include "content/public/test/test_browser_context.h" | 
|  | 18 #include "content/public/test/test_browser_thread_bundle.h" | 
|  | 19 #include "ipc/ipc_sender.h" | 
|  | 20 #include "ipc/ipc_test_sink.h" | 
|  | 21 #include "ipc/message_filter.h" | 
|  | 22 #include "storage/browser/blob/blob_data_builder.h" | 
|  | 23 #include "storage/browser/blob/blob_data_handle.h" | 
|  | 24 #include "storage/browser/blob/blob_storage_context.h" | 
|  | 25 #include "storage/common/blob_storage/blob_item_bytes_request.h" | 
|  | 26 #include "storage/common/blob_storage/blob_item_bytes_response.h" | 
|  | 27 #include "storage/common/data_element.h" | 
|  | 28 #include "testing/gmock/include/gmock/gmock.h" | 
|  | 29 #include "testing/gtest/include/gtest/gtest.h" | 
|  | 30 | 
|  | 31 using storage::BlobDataBuilder; | 
|  | 32 using storage::BlobDataHandle; | 
|  | 33 using storage::BlobItemBytesRequest; | 
|  | 34 using storage::BlobItemBytesResponse; | 
|  | 35 using storage::BlobStorageContext; | 
|  | 36 using storage::BlobTransportResult; | 
|  | 37 using storage::DataElement; | 
|  | 38 using storage::IPCBlobCreationCancelCode; | 
|  | 39 using RequestMemoryCallback = | 
|  | 40     storage::BlobAsyncBuilderHost::RequestMemoryCallback; | 
|  | 41 | 
|  | 42 namespace content { | 
|  | 43 namespace { | 
|  | 44 | 
|  | 45 const char kContentType[] = "text/plain"; | 
|  | 46 const char kContentDisposition[] = "content_disposition"; | 
|  | 47 const char kData[] = "data!!"; | 
|  | 48 const size_t kDataSize = 6; | 
|  | 49 | 
|  | 50 const size_t kTestBlobStorageIPCThresholdBytes = 20; | 
|  | 51 const size_t kTestBlobStorageMaxSharedMemoryBytes = 50; | 
|  | 52 const uint64_t kTestBlobStorageMaxFileSizeBytes = 100; | 
|  | 53 | 
|  | 54 template <typename T> | 
|  | 55 void SetPointerValue(T* pointer, T value) { | 
|  | 56   *pointer = value; | 
|  | 57 } | 
|  | 58 | 
|  | 59 class TestableBlobDispatcherHost : public BlobDispatcherHost { | 
|  | 60  public: | 
|  | 61   TestableBlobDispatcherHost(ChromeBlobStorageContext* blob_storage_context, | 
|  | 62                              IPC::TestSink* sink) | 
|  | 63       : BlobDispatcherHost(blob_storage_context), sink_(sink) { | 
|  | 64     this->SetMemoryConstantsForTesting(kTestBlobStorageIPCThresholdBytes, | 
|  | 65                                        kTestBlobStorageMaxSharedMemoryBytes, | 
|  | 66                                        kTestBlobStorageMaxFileSizeBytes); | 
|  | 67   } | 
|  | 68 | 
|  | 69   bool Send(IPC::Message* message) override { return sink_->Send(message); } | 
|  | 70 | 
|  | 71   void ShutdownForBadMessage() override { shutdown_for_bad_message_ = true; } | 
|  | 72 | 
|  | 73   bool shutdown_for_bad_message_ = false; | 
|  | 74   IPC::TestSink* sink_; | 
|  | 75 | 
|  | 76  protected: | 
|  | 77   ~TestableBlobDispatcherHost() override {} | 
|  | 78 | 
|  | 79  private: | 
|  | 80   friend class base::RefCountedThreadSafe<TestableBlobDispatcherHost>; | 
|  | 81 }; | 
|  | 82 | 
|  | 83 }  // namespace | 
|  | 84 | 
|  | 85 class BlobDispatcherHostTest : public testing::Test { | 
|  | 86  protected: | 
|  | 87   BlobDispatcherHostTest() | 
|  | 88       : browser_thread_bundle_(), | 
|  | 89         browser_context_(), | 
|  | 90         chrome_blob_storage_context_( | 
|  | 91             ChromeBlobStorageContext::GetFor(&browser_context_)) { | 
|  | 92     host_ = | 
|  | 93         new TestableBlobDispatcherHost(chrome_blob_storage_context_, &sink_); | 
|  | 94   } | 
|  | 95   ~BlobDispatcherHostTest() override {} | 
|  | 96 | 
|  | 97   void SetUp() override { | 
|  | 98     base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); | 
|  | 99     if (!command_line->HasSwitch(switches::kDisableKillAfterBadIPC)) { | 
|  | 100       command_line->AppendSwitch(switches::kDisableKillAfterBadIPC); | 
|  | 101     } | 
|  | 102     // We run the run loop to initialize the chrome blob storage context. | 
|  | 103     base::RunLoop().RunUntilIdle(); | 
|  | 104     context_ = chrome_blob_storage_context_->context(); | 
|  | 105     DCHECK(context_); | 
|  | 106   } | 
|  | 107 | 
|  | 108   void ExpectBlobNotExist(const std::string& id) { | 
|  | 109     EXPECT_FALSE(context_->registry().HasEntry(id)); | 
|  | 110     EXPECT_FALSE(host_->IsInUseInHost(id)); | 
|  | 111     EXPECT_FALSE(IsBeingBuiltInHost(id)); | 
|  | 112   } | 
|  | 113 | 
|  | 114   void AsyncShortcutBlobTransfer(const std::string& id) { | 
|  | 115     sink_.ClearMessages(); | 
|  | 116     ExpectBlobNotExist(id); | 
|  | 117     host_->OnRegisterBlobUUID(id, std::string(kContentType), | 
|  | 118                               std::string(kContentDisposition), | 
|  | 119                               std::set<std::string>()); | 
|  | 120     EXPECT_FALSE(host_->shutdown_for_bad_message_); | 
|  | 121     DataElement element; | 
|  | 122     element.SetToBytes(kData, kDataSize); | 
|  | 123     std::vector<DataElement> elements = {element}; | 
|  | 124     host_->OnStartBuildingBlob(id, elements); | 
|  | 125     EXPECT_FALSE(host_->shutdown_for_bad_message_); | 
|  | 126     ExpectDone(id); | 
|  | 127     sink_.ClearMessages(); | 
|  | 128   } | 
|  | 129 | 
|  | 130   void AsyncBlobTransfer(const std::string& id) { | 
|  | 131     sink_.ClearMessages(); | 
|  | 132     ExpectBlobNotExist(id); | 
|  | 133     host_->OnRegisterBlobUUID(id, std::string(kContentType), | 
|  | 134                               std::string(kContentDisposition), | 
|  | 135                               std::set<std::string>()); | 
|  | 136     EXPECT_FALSE(host_->shutdown_for_bad_message_); | 
|  | 137     DataElement element; | 
|  | 138     element.SetToBytesDescription(kDataSize); | 
|  | 139     std::vector<DataElement> elements = {element}; | 
|  | 140     host_->OnStartBuildingBlob(id, elements); | 
|  | 141     EXPECT_FALSE(host_->shutdown_for_bad_message_); | 
|  | 142 | 
|  | 143     // Expect our request. | 
|  | 144     std::vector<BlobItemBytesRequest> expected_requests = { | 
|  | 145         BlobItemBytesRequest::CreateIPCRequest(0, 0, 0, kDataSize)}; | 
|  | 146     ExpectRequest(id, expected_requests); | 
|  | 147     sink_.ClearMessages(); | 
|  | 148 | 
|  | 149     // Send results; | 
|  | 150     BlobItemBytesResponse response(0); | 
|  | 151     std::memcpy(response.allocate_mutable_data(kDataSize), kData, kDataSize); | 
|  | 152     std::vector<BlobItemBytesResponse> responses = {response}; | 
|  | 153     host_->OnMemoryItemResponse(id, responses); | 
|  | 154     ExpectDone(id); | 
|  | 155     sink_.ClearMessages(); | 
|  | 156   } | 
|  | 157 | 
|  | 158   void ExpectAndResetBadMessage() { | 
|  | 159     EXPECT_TRUE(host_->shutdown_for_bad_message_); | 
|  | 160     host_->shutdown_for_bad_message_ = false; | 
|  | 161   } | 
|  | 162 | 
|  | 163   void ExpectHandleEqualsData(BlobDataHandle* handle, | 
|  | 164                               const std::vector<DataElement>& data) { | 
|  | 165     scoped_ptr<storage::BlobDataSnapshot> snapshot = handle->CreateSnapshot(); | 
|  | 166     EXPECT_FALSE(handle->IsBeingBuilt()); | 
|  | 167     for (size_t i = 0; i < data.size(); i++) { | 
|  | 168       const DataElement& expected = data[i]; | 
|  | 169       const DataElement& actual = snapshot->items()[i]->data_element(); | 
|  | 170       EXPECT_EQ(expected, actual); | 
|  | 171     } | 
|  | 172     EXPECT_EQ(data.size(), snapshot->items().size()); | 
|  | 173   } | 
|  | 174 | 
|  | 175   void ExpectRequest( | 
|  | 176       const std::string& expected_uuid, | 
|  | 177       const std::vector<BlobItemBytesRequest>& expected_requests) { | 
|  | 178     EXPECT_FALSE( | 
|  | 179         sink_.GetFirstMessageMatching(BlobStorageMsg_DoneBuildingBlob::ID)); | 
|  | 180     EXPECT_FALSE( | 
|  | 181         sink_.GetFirstMessageMatching(BlobStorageMsg_CancelBuildingBlob::ID)); | 
|  | 182     const IPC::Message* message = | 
|  | 183         sink_.GetUniqueMessageMatching(BlobStorageMsg_RequestMemoryItem::ID); | 
|  | 184     ASSERT_TRUE(message); | 
|  | 185     base::Tuple<std::string, std::vector<storage::BlobItemBytesRequest>, | 
|  | 186                 std::vector<base::SharedMemoryHandle>, | 
|  | 187                 std::vector<IPC::PlatformFileForTransit>> | 
|  | 188         args; | 
|  | 189     BlobStorageMsg_RequestMemoryItem::Read(message, &args); | 
|  | 190     EXPECT_EQ(expected_uuid, base::get<0>(args)); | 
|  | 191     std::vector<BlobItemBytesRequest> requests = base::get<1>(args); | 
|  | 192     ASSERT_EQ(requests.size(), expected_requests.size()); | 
|  | 193     for (size_t i = 0; i < expected_requests.size(); ++i) { | 
|  | 194       EXPECT_EQ(expected_requests[i], requests[i]); | 
|  | 195     } | 
|  | 196   } | 
|  | 197 | 
|  | 198   void ExpectRequestWithSharedMemoryHandles( | 
|  | 199       const std::string& expected_uuid, | 
|  | 200       const std::vector<BlobItemBytesRequest>& expected_requests, | 
|  | 201       std::vector<base::SharedMemoryHandle>* shared_memory_handles) { | 
|  | 202     EXPECT_FALSE( | 
|  | 203         sink_.GetFirstMessageMatching(BlobStorageMsg_DoneBuildingBlob::ID)); | 
|  | 204     EXPECT_FALSE( | 
|  | 205         sink_.GetFirstMessageMatching(BlobStorageMsg_CancelBuildingBlob::ID)); | 
|  | 206     const IPC::Message* message = | 
|  | 207         sink_.GetUniqueMessageMatching(BlobStorageMsg_RequestMemoryItem::ID); | 
|  | 208     ASSERT_TRUE(message); | 
|  | 209     base::Tuple<std::string, std::vector<storage::BlobItemBytesRequest>, | 
|  | 210                 std::vector<base::SharedMemoryHandle>, | 
|  | 211                 std::vector<IPC::PlatformFileForTransit>> | 
|  | 212         args; | 
|  | 213     BlobStorageMsg_RequestMemoryItem::Read(message, &args); | 
|  | 214     EXPECT_EQ(expected_uuid, base::get<0>(args)); | 
|  | 215     std::vector<BlobItemBytesRequest> requests = base::get<1>(args); | 
|  | 216     ASSERT_EQ(requests.size(), expected_requests.size()); | 
|  | 217     for (size_t i = 0; i < expected_requests.size(); ++i) { | 
|  | 218       EXPECT_EQ(expected_requests[i], requests[i]); | 
|  | 219     } | 
|  | 220     *shared_memory_handles = std::move(base::get<2>(args)); | 
|  | 221   } | 
|  | 222 | 
|  | 223   void ExpectCancel(const std::string& expected_uuid, | 
|  | 224                     IPCBlobCreationCancelCode code) { | 
|  | 225     EXPECT_FALSE( | 
|  | 226         sink_.GetFirstMessageMatching(BlobStorageMsg_RequestMemoryItem::ID)); | 
|  | 227     EXPECT_FALSE( | 
|  | 228         sink_.GetFirstMessageMatching(BlobStorageMsg_DoneBuildingBlob::ID)); | 
|  | 229     const IPC::Message* message = | 
|  | 230         sink_.GetUniqueMessageMatching(BlobStorageMsg_CancelBuildingBlob::ID); | 
|  | 231     ASSERT_TRUE(message); | 
|  | 232     base::Tuple<std::string, IPCBlobCreationCancelCode> args; | 
|  | 233     BlobStorageMsg_CancelBuildingBlob::Read(message, &args); | 
|  | 234     EXPECT_EQ(expected_uuid, base::get<0>(args)); | 
|  | 235     EXPECT_EQ(code, base::get<1>(args)); | 
|  | 236   } | 
|  | 237 | 
|  | 238   void ExpectDone(const std::string& expected_uuid) { | 
|  | 239     EXPECT_FALSE( | 
|  | 240         sink_.GetFirstMessageMatching(BlobStorageMsg_RequestMemoryItem::ID)); | 
|  | 241     EXPECT_FALSE( | 
|  | 242         sink_.GetFirstMessageMatching(BlobStorageMsg_CancelBuildingBlob::ID)); | 
|  | 243     const IPC::Message* message = | 
|  | 244         sink_.GetUniqueMessageMatching(BlobStorageMsg_DoneBuildingBlob::ID); | 
|  | 245     base::Tuple<std::string> args; | 
|  | 246     BlobStorageMsg_DoneBuildingBlob::Read(message, &args); | 
|  | 247     EXPECT_EQ(expected_uuid, base::get<0>(args)); | 
|  | 248   } | 
|  | 249 | 
|  | 250   bool IsBeingBuiltInHost(const std::string& uuid) { | 
|  | 251     return host_->async_builder_.IsBeingBuilt(uuid); | 
|  | 252   } | 
|  | 253 | 
|  | 254   IPC::TestSink sink_; | 
|  | 255   TestBrowserThreadBundle browser_thread_bundle_; | 
|  | 256   TestBrowserContext browser_context_; | 
|  | 257   ChromeBlobStorageContext* chrome_blob_storage_context_; | 
|  | 258   BlobStorageContext* context_ = nullptr; | 
|  | 259   scoped_refptr<TestableBlobDispatcherHost> host_; | 
|  | 260 }; | 
|  | 261 | 
|  | 262 TEST_F(BlobDispatcherHostTest, EmptyUUIDs) { | 
|  | 263   host_->OnRegisterBlobUUID("", "", "", std::set<std::string>()); | 
|  | 264   ExpectAndResetBadMessage(); | 
|  | 265   host_->OnStartBuildingBlob("", std::vector<DataElement>()); | 
|  | 266   ExpectAndResetBadMessage(); | 
|  | 267   host_->OnMemoryItemResponse("", std::vector<BlobItemBytesResponse>()); | 
|  | 268   ExpectAndResetBadMessage(); | 
|  | 269   host_->OnCancelBuildingBlob("", IPCBlobCreationCancelCode::UNKNOWN); | 
|  | 270   ExpectAndResetBadMessage(); | 
|  | 271 } | 
|  | 272 | 
|  | 273 TEST_F(BlobDispatcherHostTest, Shortcut) { | 
|  | 274   const std::string kId = "uuid1"; | 
|  | 275   AsyncShortcutBlobTransfer(kId); | 
|  | 276   EXPECT_TRUE(context_->registry().HasEntry(kId)); | 
|  | 277   scoped_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId); | 
|  | 278   EXPECT_TRUE(handle); | 
|  | 279 | 
|  | 280   DataElement expected; | 
|  | 281   expected.SetToBytes(kData, kDataSize); | 
|  | 282   std::vector<DataElement> elements = {expected}; | 
|  | 283   ExpectHandleEqualsData(handle.get(), elements); | 
|  | 284 } | 
|  | 285 | 
|  | 286 TEST_F(BlobDispatcherHostTest, RegularTransfer) { | 
|  | 287   const std::string kId = "uuid1"; | 
|  | 288   AsyncBlobTransfer(kId); | 
|  | 289   EXPECT_TRUE(context_->registry().HasEntry(kId)); | 
|  | 290   scoped_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId); | 
|  | 291   EXPECT_TRUE(handle); | 
|  | 292 | 
|  | 293   DataElement expected; | 
|  | 294   expected.SetToBytes(kData, kDataSize); | 
|  | 295   std::vector<DataElement> elements = {expected}; | 
|  | 296   ExpectHandleEqualsData(handle.get(), elements); | 
|  | 297 } | 
|  | 298 | 
|  | 299 TEST_F(BlobDispatcherHostTest, SharedMemoryTransfer) { | 
|  | 300   const std::string kId = "uuid1"; | 
|  | 301   const size_t kLargeSize = kTestBlobStorageMaxSharedMemoryBytes * 2; | 
|  | 302   std::vector<base::SharedMemoryHandle> shared_memory_handles; | 
|  | 303 | 
|  | 304   ExpectBlobNotExist(kId); | 
|  | 305   host_->OnRegisterBlobUUID(kId, std::string(kContentType), | 
|  | 306                             std::string(kContentDisposition), | 
|  | 307                             std::set<std::string>()); | 
|  | 308   // Grab the handle. | 
|  | 309   scoped_ptr<BlobDataHandle> blob_data_handle = | 
|  | 310       context_->GetBlobDataFromUUID(kId); | 
|  | 311   bool built = false; | 
|  | 312   blob_data_handle->RunOnConstructionComplete( | 
|  | 313       base::Bind(&SetPointerValue<bool>, &built)); | 
|  | 314   EXPECT_FALSE(built); | 
|  | 315 | 
|  | 316   EXPECT_FALSE(host_->shutdown_for_bad_message_); | 
|  | 317   DataElement element; | 
|  | 318   element.SetToBytesDescription(kLargeSize); | 
|  | 319   std::vector<DataElement> elements = {element}; | 
|  | 320   host_->OnStartBuildingBlob(kId, elements); | 
|  | 321   EXPECT_FALSE(host_->shutdown_for_bad_message_); | 
|  | 322 | 
|  | 323   // Expect our first request. | 
|  | 324   std::vector<BlobItemBytesRequest> expected_requests = { | 
|  | 325       BlobItemBytesRequest::CreateSharedMemoryRequest( | 
|  | 326           0 /* request_number */, 0 /* renderer_item_index */, | 
|  | 327           0 /* renderer_item_offset */, | 
|  | 328           static_cast<uint64_t>( | 
|  | 329               kTestBlobStorageMaxSharedMemoryBytes) /* size */, | 
|  | 330           0 /* handle_index */, 0 /* handle_offset */)}; | 
|  | 331   ExpectRequestWithSharedMemoryHandles(kId, expected_requests, | 
|  | 332                                        &shared_memory_handles); | 
|  | 333   sink_.ClearMessages(); | 
|  | 334 | 
|  | 335   // Populate the shared memory. | 
|  | 336   EXPECT_EQ(1u, shared_memory_handles.size()); | 
|  | 337   EXPECT_TRUE(base::SharedMemory::IsHandleValid(shared_memory_handles[0])); | 
|  | 338   { | 
|  | 339     base::SharedMemory memory( | 
|  | 340         base::SharedMemory::DuplicateHandle(shared_memory_handles[0]), false); | 
|  | 341     memory.Map(kTestBlobStorageMaxSharedMemoryBytes); | 
|  | 342     std::memset(memory.memory(), 'X', kTestBlobStorageMaxSharedMemoryBytes); | 
|  | 343     memory.Close(); | 
|  | 344   } | 
|  | 345 | 
|  | 346   // Send the confirmation. | 
|  | 347   std::vector<BlobItemBytesResponse> responses = {BlobItemBytesResponse(0)}; | 
|  | 348   host_->OnMemoryItemResponse(kId, responses); | 
|  | 349 | 
|  | 350   // Expect our second request. | 
|  | 351   expected_requests = {BlobItemBytesRequest::CreateSharedMemoryRequest( | 
|  | 352       1 /* request_number */, 0 /* renderer_item_index */, | 
|  | 353       static_cast<uint64_t>( | 
|  | 354           kTestBlobStorageMaxSharedMemoryBytes) /* renderer_item_offset */, | 
|  | 355       static_cast<uint64_t>(kTestBlobStorageMaxSharedMemoryBytes) /* size */, | 
|  | 356       0 /* handle_index */, 0 /* handle_offset */)}; | 
|  | 357   ExpectRequestWithSharedMemoryHandles(kId, expected_requests, | 
|  | 358                                        &shared_memory_handles); | 
|  | 359   sink_.ClearMessages(); | 
|  | 360 | 
|  | 361   // Populate the shared memory. | 
|  | 362   EXPECT_EQ(1u, shared_memory_handles.size()); | 
|  | 363   EXPECT_TRUE(base::SharedMemory::IsHandleValid(shared_memory_handles[0])); | 
|  | 364   { | 
|  | 365     base::SharedMemory memory( | 
|  | 366         base::SharedMemory::DuplicateHandle(shared_memory_handles[0]), false); | 
|  | 367     memory.Map(kTestBlobStorageMaxSharedMemoryBytes); | 
|  | 368     std::memset(memory.memory(), 'Z', kTestBlobStorageMaxSharedMemoryBytes); | 
|  | 369     memory.Close(); | 
|  | 370   } | 
|  | 371   // Send the confirmation. | 
|  | 372   responses = {BlobItemBytesResponse(1)}; | 
|  | 373   host_->OnMemoryItemResponse(kId, responses); | 
|  | 374 | 
|  | 375   ExpectDone(kId); | 
|  | 376   sink_.ClearMessages(); | 
|  | 377   base::RunLoop().RunUntilIdle(); | 
|  | 378   EXPECT_TRUE(built); | 
|  | 379   EXPECT_TRUE(context_->registry().HasEntry(kId)); | 
|  | 380   scoped_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId); | 
|  | 381   EXPECT_TRUE(handle); | 
|  | 382 | 
|  | 383   DataElement expected; | 
|  | 384   expected.SetToAllocatedBytes(kLargeSize / 2); | 
|  | 385   std::memset(expected.mutable_bytes(), 'X', kLargeSize / 2); | 
|  | 386   elements = {expected}; | 
|  | 387   std::memset(expected.mutable_bytes(), 'Z', kLargeSize / 2); | 
|  | 388   elements.push_back(expected); | 
|  | 389   ExpectHandleEqualsData(handle.get(), elements); | 
|  | 390 } | 
|  | 391 | 
|  | 392 TEST_F(BlobDispatcherHostTest, OnCancelBuildingBlob) { | 
|  | 393   const std::string kId("id"); | 
|  | 394   // We ignore blobs that are unknown, as it could have been cancelled earlier | 
|  | 395   // and the renderer didn't know about it yet. | 
|  | 396   host_->OnCancelBuildingBlob(kId, IPCBlobCreationCancelCode::UNKNOWN); | 
|  | 397   EXPECT_FALSE(host_->shutdown_for_bad_message_); | 
|  | 398 | 
|  | 399   // Start building blob. | 
|  | 400   host_->OnRegisterBlobUUID(kId, std::string(kContentType), | 
|  | 401                             std::string(kContentDisposition), | 
|  | 402                             std::set<std::string>()); | 
|  | 403   EXPECT_FALSE(host_->shutdown_for_bad_message_); | 
|  | 404   DataElement element; | 
|  | 405   element.SetToBytesDescription(kDataSize); | 
|  | 406   std::vector<DataElement> elements = {element}; | 
|  | 407   host_->OnStartBuildingBlob(kId, elements); | 
|  | 408   // It should have requested memory here. | 
|  | 409   EXPECT_FALSE(host_->shutdown_for_bad_message_); | 
|  | 410   sink_.ClearMessages(); | 
|  | 411 | 
|  | 412   // Cancel in middle of construction. | 
|  | 413   host_->OnCancelBuildingBlob(kId, IPCBlobCreationCancelCode::UNKNOWN); | 
|  | 414   EXPECT_TRUE(context_->registry().HasEntry(kId)); | 
|  | 415   EXPECT_TRUE(host_->IsInUseInHost(kId)); | 
|  | 416   EXPECT_FALSE(IsBeingBuiltInHost(kId)); | 
|  | 417   // Check that's it's broken. | 
|  | 418   scoped_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId); | 
|  | 419   EXPECT_TRUE(handle->IsBroken()); | 
|  | 420   handle.reset(); | 
|  | 421   base::RunLoop().RunUntilIdle(); | 
|  | 422 | 
|  | 423   // Get rid of it in the host. | 
|  | 424   host_->OnDecrementBlobRefCount(kId); | 
|  | 425   ExpectBlobNotExist(kId); | 
|  | 426 | 
|  | 427   // Create blob again to verify we don't have any old construction state lying | 
|  | 428   // around. | 
|  | 429   AsyncBlobTransfer(kId); | 
|  | 430 | 
|  | 431   // Check data. | 
|  | 432   handle = context_->GetBlobDataFromUUID(kId); | 
|  | 433   EXPECT_TRUE(handle); | 
|  | 434   DataElement expected; | 
|  | 435   expected.SetToBytes(kData, kDataSize); | 
|  | 436   std::vector<DataElement> expecteds = {expected}; | 
|  | 437   ExpectHandleEqualsData(handle.get(), expecteds); | 
|  | 438 | 
|  | 439   // Verify we can't cancel after the fact. | 
|  | 440   host_->OnCancelBuildingBlob(kId, IPCBlobCreationCancelCode::UNKNOWN); | 
|  | 441   ExpectAndResetBadMessage(); | 
|  | 442 } | 
|  | 443 | 
|  | 444 TEST_F(BlobDispatcherHostTest, BlobDataWithHostDeletion) { | 
|  | 445   // Build up a basic blob. | 
|  | 446   const std::string kId("id"); | 
|  | 447   AsyncShortcutBlobTransfer(kId); | 
|  | 448   scoped_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId); | 
|  | 449   EXPECT_TRUE(handle); | 
|  | 450 | 
|  | 451   // Kill the host. | 
|  | 452   host_ = nullptr; | 
|  | 453   base::RunLoop().RunUntilIdle(); | 
|  | 454   // Should still be there due to the handle. | 
|  | 455   scoped_ptr<BlobDataHandle> another_handle = | 
|  | 456       context_->GetBlobDataFromUUID(kId); | 
|  | 457   EXPECT_TRUE(another_handle); | 
|  | 458 | 
|  | 459   // Should disappear after dropping both handles. | 
|  | 460   handle.reset(); | 
|  | 461   another_handle.reset(); | 
|  | 462   base::RunLoop().RunUntilIdle(); | 
|  | 463 | 
|  | 464   handle = context_->GetBlobDataFromUUID(kId); | 
|  | 465   EXPECT_FALSE(handle); | 
|  | 466 } | 
|  | 467 | 
|  | 468 TEST_F(BlobDispatcherHostTest, BlobReferenceWhileConstructing) { | 
|  | 469   const std::string kId("id"); | 
|  | 470 | 
|  | 471   // Start building blob. | 
|  | 472   host_->OnRegisterBlobUUID(kId, std::string(kContentType), | 
|  | 473                             std::string(kContentDisposition), | 
|  | 474                             std::set<std::string>()); | 
|  | 475 | 
|  | 476   // Grab the handle. | 
|  | 477   scoped_ptr<BlobDataHandle> blob_data_handle = | 
|  | 478       context_->GetBlobDataFromUUID(kId); | 
|  | 479   EXPECT_TRUE(blob_data_handle); | 
|  | 480   EXPECT_TRUE(blob_data_handle->IsBeingBuilt()); | 
|  | 481   bool built = false; | 
|  | 482   blob_data_handle->RunOnConstructionComplete( | 
|  | 483       base::Bind(&SetPointerValue<bool>, &built)); | 
|  | 484 | 
|  | 485   // Continue building. | 
|  | 486   DataElement element; | 
|  | 487   element.SetToBytesDescription(kDataSize); | 
|  | 488   std::vector<DataElement> elements = {element}; | 
|  | 489   host_->OnStartBuildingBlob(kId, elements); | 
|  | 490   sink_.ClearMessages(); | 
|  | 491 | 
|  | 492   // Send data. | 
|  | 493   BlobItemBytesResponse response(0); | 
|  | 494   std::memcpy(response.allocate_mutable_data(kDataSize), kData, kDataSize); | 
|  | 495   std::vector<BlobItemBytesResponse> responses = {response}; | 
|  | 496   sink_.ClearMessages(); | 
|  | 497   host_->OnMemoryItemResponse(kId, responses); | 
|  | 498 | 
|  | 499   ExpectDone(kId); | 
|  | 500   base::RunLoop().RunUntilIdle(); | 
|  | 501   EXPECT_TRUE(built); | 
|  | 502 } | 
|  | 503 | 
|  | 504 TEST_F(BlobDispatcherHostTest, BlobReferenceWhileShortcutConstructing) { | 
|  | 505   const std::string kId("id"); | 
|  | 506 | 
|  | 507   // Start building blob. | 
|  | 508   host_->OnRegisterBlobUUID(kId, std::string(kContentType), | 
|  | 509                             std::string(kContentDisposition), | 
|  | 510                             std::set<std::string>()); | 
|  | 511 | 
|  | 512   // Grab the handle. | 
|  | 513   scoped_ptr<BlobDataHandle> blob_data_handle = | 
|  | 514       context_->GetBlobDataFromUUID(kId); | 
|  | 515   EXPECT_TRUE(blob_data_handle); | 
|  | 516   EXPECT_TRUE(blob_data_handle->IsBeingBuilt()); | 
|  | 517   bool built = false; | 
|  | 518   blob_data_handle->RunOnConstructionComplete( | 
|  | 519       base::Bind(&SetPointerValue<bool>, &built)); | 
|  | 520 | 
|  | 521   // Continue building. | 
|  | 522   DataElement element; | 
|  | 523   element.SetToBytes(kData, kDataSize); | 
|  | 524   std::vector<DataElement> elements = {element}; | 
|  | 525   host_->OnStartBuildingBlob(kId, elements); | 
|  | 526   ExpectDone(kId); | 
|  | 527   base::RunLoop().RunUntilIdle(); | 
|  | 528   EXPECT_TRUE(built); | 
|  | 529 } | 
|  | 530 | 
|  | 531 TEST_F(BlobDispatcherHostTest, BlobReferenceWhileConstructingCancelled) { | 
|  | 532   const std::string kId("id"); | 
|  | 533 | 
|  | 534   // Start building blob. | 
|  | 535   host_->OnRegisterBlobUUID(kId, std::string(kContentType), | 
|  | 536                             std::string(kContentDisposition), | 
|  | 537                             std::set<std::string>()); | 
|  | 538 | 
|  | 539   // Grab the handle. | 
|  | 540   scoped_ptr<BlobDataHandle> blob_data_handle = | 
|  | 541       context_->GetBlobDataFromUUID(kId); | 
|  | 542   EXPECT_TRUE(blob_data_handle); | 
|  | 543   EXPECT_TRUE(blob_data_handle->IsBeingBuilt()); | 
|  | 544   bool built = true; | 
|  | 545   blob_data_handle->RunOnConstructionComplete( | 
|  | 546       base::Bind(&SetPointerValue<bool>, &built)); | 
|  | 547 | 
|  | 548   // Cancel in middle of construction. | 
|  | 549   host_->OnCancelBuildingBlob(kId, IPCBlobCreationCancelCode::UNKNOWN); | 
|  | 550   base::RunLoop().RunUntilIdle(); | 
|  | 551   EXPECT_TRUE(context_->registry().HasEntry(kId)); | 
|  | 552   EXPECT_TRUE(host_->IsInUseInHost(kId)); | 
|  | 553   EXPECT_FALSE(IsBeingBuiltInHost(kId)); | 
|  | 554   EXPECT_TRUE(blob_data_handle->IsBroken()); | 
|  | 555   EXPECT_FALSE(built); | 
|  | 556   built = true; | 
|  | 557   blob_data_handle->RunOnConstructionComplete( | 
|  | 558       base::Bind(&SetPointerValue<bool>, &built)); | 
|  | 559   EXPECT_FALSE(built); | 
|  | 560 | 
|  | 561   // Remove it. | 
|  | 562   blob_data_handle.reset(); | 
|  | 563   base::RunLoop().RunUntilIdle(); | 
|  | 564   EXPECT_TRUE(context_->registry().HasEntry(kId)); | 
|  | 565   host_->OnDecrementBlobRefCount(kId); | 
|  | 566   ExpectBlobNotExist(kId); | 
|  | 567 } | 
|  | 568 | 
|  | 569 TEST_F(BlobDispatcherHostTest, DecrementRefAfterRegister) { | 
|  | 570   const std::string kId("id"); | 
|  | 571   // Decrement the refcount while building (renderer blob gc'd before | 
|  | 572   // construction was completed). | 
|  | 573   host_->OnRegisterBlobUUID(kId, std::string(kContentType), | 
|  | 574                             std::string(kContentDisposition), | 
|  | 575                             std::set<std::string>()); | 
|  | 576   EXPECT_TRUE(context_->registry().HasEntry(kId)); | 
|  | 577   host_->OnDecrementBlobRefCount(kId); | 
|  | 578   EXPECT_FALSE(context_->registry().HasEntry(kId)); | 
|  | 579   EXPECT_FALSE(IsBeingBuiltInHost(kId)); | 
|  | 580   ExpectCancel(kId, | 
|  | 581                IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING); | 
|  | 582   sink_.ClearMessages(); | 
|  | 583 | 
|  | 584   // Do the same, but this time grab a handle before we decrement. | 
|  | 585   host_->OnRegisterBlobUUID(kId, std::string(kContentType), | 
|  | 586                             std::string(kContentDisposition), | 
|  | 587                             std::set<std::string>()); | 
|  | 588   scoped_ptr<BlobDataHandle> blob_data_handle = | 
|  | 589       context_->GetBlobDataFromUUID(kId); | 
|  | 590   host_->OnDecrementBlobRefCount(kId); | 
|  | 591   EXPECT_TRUE(context_->registry().HasEntry(kId)); | 
|  | 592   EXPECT_TRUE(IsBeingBuiltInHost(kId)); | 
|  | 593 | 
|  | 594   // Finish up the blob, and verify we got the done message. | 
|  | 595   DataElement element; | 
|  | 596   element.SetToBytes(kData, kDataSize); | 
|  | 597   std::vector<DataElement> elements = {element}; | 
|  | 598   host_->OnStartBuildingBlob(kId, elements); | 
|  | 599   EXPECT_FALSE(host_->shutdown_for_bad_message_); | 
|  | 600   ExpectDone(kId); | 
|  | 601   sink_.ClearMessages(); | 
|  | 602   // Get rid of the handle, and verify it's gone. | 
|  | 603   blob_data_handle.reset(); | 
|  | 604   base::RunLoop().RunUntilIdle(); | 
|  | 605   // Check that it's no longer around. | 
|  | 606   EXPECT_FALSE(context_->registry().HasEntry(kId)); | 
|  | 607   EXPECT_FALSE(IsBeingBuiltInHost(kId)); | 
|  | 608 } | 
|  | 609 | 
|  | 610 TEST_F(BlobDispatcherHostTest, DecrementRefAfterOnStart) { | 
|  | 611   const std::string kId("id"); | 
|  | 612 | 
|  | 613   // Decrement the refcount while building, after we call OnStartBuildlingBlob. | 
|  | 614   host_->OnRegisterBlobUUID(kId, std::string(kContentType), | 
|  | 615                             std::string(kContentDisposition), | 
|  | 616                             std::set<std::string>()); | 
|  | 617   EXPECT_FALSE(host_->shutdown_for_bad_message_); | 
|  | 618   DataElement element; | 
|  | 619   element.SetToBytesDescription(kDataSize); | 
|  | 620   std::vector<DataElement> elements = {element}; | 
|  | 621   host_->OnStartBuildingBlob(kId, elements); | 
|  | 622   EXPECT_FALSE(host_->shutdown_for_bad_message_); | 
|  | 623 | 
|  | 624   std::vector<BlobItemBytesRequest> expected_requests = { | 
|  | 625       BlobItemBytesRequest::CreateIPCRequest(0, 0, 0, kDataSize)}; | 
|  | 626   ExpectRequest(kId, expected_requests); | 
|  | 627   sink_.ClearMessages(); | 
|  | 628   EXPECT_TRUE(context_->registry().HasEntry(kId)); | 
|  | 629   host_->OnDecrementBlobRefCount(kId); | 
|  | 630   EXPECT_FALSE(context_->registry().HasEntry(kId)); | 
|  | 631   EXPECT_FALSE(IsBeingBuiltInHost(kId)); | 
|  | 632   ExpectCancel(kId, | 
|  | 633                IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING); | 
|  | 634   sink_.ClearMessages(); | 
|  | 635 | 
|  | 636   // Do the same, but this time grab a handle to keep it alive. | 
|  | 637   host_->OnRegisterBlobUUID(kId, std::string(kContentType), | 
|  | 638                             std::string(kContentDisposition), | 
|  | 639                             std::set<std::string>()); | 
|  | 640   EXPECT_FALSE(host_->shutdown_for_bad_message_); | 
|  | 641   host_->OnStartBuildingBlob(kId, elements); | 
|  | 642   EXPECT_FALSE(host_->shutdown_for_bad_message_); | 
|  | 643   ExpectRequest(kId, expected_requests); | 
|  | 644   sink_.ClearMessages(); | 
|  | 645   EXPECT_TRUE(context_->registry().HasEntry(kId)); | 
|  | 646   // Grab the handle before decrementing. | 
|  | 647   scoped_ptr<BlobDataHandle> blob_data_handle = | 
|  | 648       context_->GetBlobDataFromUUID(kId); | 
|  | 649   host_->OnDecrementBlobRefCount(kId); | 
|  | 650   EXPECT_TRUE(context_->registry().HasEntry(kId)); | 
|  | 651   EXPECT_TRUE(IsBeingBuiltInHost(kId)); | 
|  | 652 | 
|  | 653   // We finish the blob, and verify that we send 'Done' back to the renderer. | 
|  | 654   BlobItemBytesResponse response(0); | 
|  | 655   std::memcpy(response.allocate_mutable_data(kDataSize), kData, kDataSize); | 
|  | 656   std::vector<BlobItemBytesResponse> responses = {response}; | 
|  | 657   host_->OnMemoryItemResponse(kId, responses); | 
|  | 658   ExpectDone(kId); | 
|  | 659   sink_.ClearMessages(); | 
|  | 660   // Check that it's still around. | 
|  | 661   EXPECT_TRUE(context_->registry().HasEntry(kId)); | 
|  | 662   EXPECT_FALSE(IsBeingBuiltInHost(kId)); | 
|  | 663 | 
|  | 664   // Get rid of the handle, and verify it's gone. | 
|  | 665   blob_data_handle.reset(); | 
|  | 666   base::RunLoop().RunUntilIdle(); | 
|  | 667   // Check that it's no longer around. | 
|  | 668   EXPECT_FALSE(context_->registry().HasEntry(kId)); | 
|  | 669   EXPECT_FALSE(IsBeingBuiltInHost(kId)); | 
|  | 670 } | 
|  | 671 | 
|  | 672 TEST_F(BlobDispatcherHostTest, DecrementRefAfterOnStartWithHandle) { | 
|  | 673   const std::string kId("id"); | 
|  | 674   // Case 3: Decrement the refcount while building, after we call | 
|  | 675   // OnStartBuildlingBlob, except we have another handle. | 
|  | 676   host_->OnRegisterBlobUUID(kId, std::string(kContentType), | 
|  | 677                             std::string(kContentDisposition), | 
|  | 678                             std::set<std::string>()); | 
|  | 679   EXPECT_FALSE(host_->shutdown_for_bad_message_); | 
|  | 680 | 
|  | 681   scoped_ptr<BlobDataHandle> blob_data_handle = | 
|  | 682       context_->GetBlobDataFromUUID(kId); | 
|  | 683   EXPECT_TRUE(blob_data_handle->IsBeingBuilt()); | 
|  | 684   bool built = true; | 
|  | 685   blob_data_handle->RunOnConstructionComplete( | 
|  | 686       base::Bind(&SetPointerValue<bool>, &built)); | 
|  | 687 | 
|  | 688   DataElement element; | 
|  | 689   element.SetToBytesDescription(kDataSize); | 
|  | 690   std::vector<DataElement> elements = {element}; | 
|  | 691   host_->OnStartBuildingBlob(kId, elements); | 
|  | 692   EXPECT_FALSE(host_->shutdown_for_bad_message_); | 
|  | 693 | 
|  | 694   // Check that we got the expected request. | 
|  | 695   std::vector<BlobItemBytesRequest> expected_requests = { | 
|  | 696       BlobItemBytesRequest::CreateIPCRequest(0, 0, 0, kDataSize)}; | 
|  | 697   ExpectRequest(kId, expected_requests); | 
|  | 698   sink_.ClearMessages(); | 
|  | 699   EXPECT_TRUE(context_->registry().HasEntry(kId)); | 
|  | 700   EXPECT_TRUE(IsBeingBuiltInHost(kId)); | 
|  | 701   // Decrement, simulating where the ref goes out of scope in renderer. | 
|  | 702   host_->OnDecrementBlobRefCount(kId); | 
|  | 703   // We still have the blob as it's not done. | 
|  | 704   EXPECT_TRUE(context_->registry().HasEntry(kId)); | 
|  | 705   EXPECT_TRUE(blob_data_handle->IsBeingBuilt()); | 
|  | 706   EXPECT_TRUE(IsBeingBuiltInHost(kId)); | 
|  | 707   // Cancel to clean up. | 
|  | 708   host_->OnCancelBuildingBlob(kId, IPCBlobCreationCancelCode::UNKNOWN); | 
|  | 709   // Run loop to propagate the handle decrement in the host. | 
|  | 710   base::RunLoop().RunUntilIdle(); | 
|  | 711   // We still have the entry because of our earlier handle. | 
|  | 712   EXPECT_TRUE(context_->registry().HasEntry(kId)); | 
|  | 713   EXPECT_FALSE(IsBeingBuiltInHost(kId)); | 
|  | 714   sink_.ClearMessages(); | 
|  | 715 | 
|  | 716   // Should disappear after dropping the handle. | 
|  | 717   EXPECT_TRUE(blob_data_handle->IsBroken()); | 
|  | 718   blob_data_handle.reset(); | 
|  | 719   base::RunLoop().RunUntilIdle(); | 
|  | 720   EXPECT_FALSE(context_->registry().HasEntry(kId)); | 
|  | 721 } | 
|  | 722 | 
|  | 723 TEST_F(BlobDispatcherHostTest, HostDisconnectAfterRegisterWithHandle) { | 
|  | 724   const std::string kId("id"); | 
|  | 725 | 
|  | 726   // Delete host with a handle to the blob. | 
|  | 727   host_->OnRegisterBlobUUID(kId, std::string(kContentType), | 
|  | 728                             std::string(kContentDisposition), | 
|  | 729                             std::set<std::string>()); | 
|  | 730 | 
|  | 731   scoped_ptr<BlobDataHandle> blob_data_handle = | 
|  | 732       context_->GetBlobDataFromUUID(kId); | 
|  | 733   EXPECT_TRUE(blob_data_handle->IsBeingBuilt()); | 
|  | 734   bool built = true; | 
|  | 735   blob_data_handle->RunOnConstructionComplete( | 
|  | 736       base::Bind(&SetPointerValue<bool>, &built)); | 
|  | 737   // Get rid of host, which was doing the constructing. | 
|  | 738   host_ = nullptr; | 
|  | 739   EXPECT_FALSE(blob_data_handle->IsBeingBuilt()); | 
|  | 740   base::RunLoop().RunUntilIdle(); | 
|  | 741   EXPECT_FALSE(built); | 
|  | 742 | 
|  | 743   // Should still be there due to the handle. | 
|  | 744   scoped_ptr<BlobDataHandle> another_handle = | 
|  | 745       context_->GetBlobDataFromUUID(kId); | 
|  | 746   EXPECT_TRUE(another_handle); | 
|  | 747 | 
|  | 748   // Should disappear after dropping both handles. | 
|  | 749   blob_data_handle.reset(); | 
|  | 750   another_handle.reset(); | 
|  | 751   base::RunLoop().RunUntilIdle(); | 
|  | 752   EXPECT_FALSE(context_->registry().HasEntry(kId)); | 
|  | 753 } | 
|  | 754 | 
|  | 755 TEST_F(BlobDispatcherHostTest, HostDisconnectAfterOnStart) { | 
|  | 756   const std::string kId("id"); | 
|  | 757 | 
|  | 758   // Host deleted after OnStartBuilding. | 
|  | 759   host_->OnRegisterBlobUUID(kId, std::string(kContentType), | 
|  | 760                             std::string(kContentDisposition), | 
|  | 761                             std::set<std::string>()); | 
|  | 762 | 
|  | 763   DataElement element; | 
|  | 764   element.SetToBytesDescription(kDataSize); | 
|  | 765   std::vector<DataElement> elements = {element}; | 
|  | 766   host_->OnStartBuildingBlob(kId, elements); | 
|  | 767 | 
|  | 768   std::vector<BlobItemBytesRequest> expected_requests = { | 
|  | 769       BlobItemBytesRequest::CreateIPCRequest(0, 0, 0, kDataSize)}; | 
|  | 770   ExpectRequest(kId, expected_requests); | 
|  | 771   sink_.ClearMessages(); | 
|  | 772   host_ = nullptr; | 
|  | 773   // We need to run the message loop because of the handle in the async builder. | 
|  | 774   base::RunLoop().RunUntilIdle(); | 
|  | 775   EXPECT_FALSE(context_->registry().HasEntry(kId)); | 
|  | 776 } | 
|  | 777 | 
|  | 778 TEST_F(BlobDispatcherHostTest, HostDisconnectAfterOnMemoryResponse) { | 
|  | 779   const std::string kId("id"); | 
|  | 780 | 
|  | 781   // Host deleted after OnMemoryItemResponse. | 
|  | 782   host_->OnRegisterBlobUUID(kId, std::string(kContentType), | 
|  | 783                             std::string(kContentDisposition), | 
|  | 784                             std::set<std::string>()); | 
|  | 785 | 
|  | 786   // Create list of two items. | 
|  | 787   DataElement element; | 
|  | 788   element.SetToBytesDescription(kDataSize); | 
|  | 789   std::vector<DataElement> elements = {element, element}; | 
|  | 790   host_->OnStartBuildingBlob(kId, elements); | 
|  | 791   std::vector<BlobItemBytesRequest> expected_requests = { | 
|  | 792       BlobItemBytesRequest::CreateIPCRequest(0, 0, 0, kDataSize), | 
|  | 793       BlobItemBytesRequest::CreateIPCRequest(1, 1, 0, kDataSize)}; | 
|  | 794   ExpectRequest(kId, expected_requests); | 
|  | 795   sink_.ClearMessages(); | 
|  | 796 | 
|  | 797   // Send just one response so the blob isn't 'done' yet. | 
|  | 798   BlobItemBytesResponse response(0); | 
|  | 799   std::memcpy(response.allocate_mutable_data(kDataSize), kData, kDataSize); | 
|  | 800   std::vector<BlobItemBytesResponse> responses = {response}; | 
|  | 801   host_->OnMemoryItemResponse(kId, responses); | 
|  | 802   EXPECT_EQ(0u, sink_.message_count()); | 
|  | 803 | 
|  | 804   host_ = nullptr; | 
|  | 805   base::RunLoop().RunUntilIdle(); | 
|  | 806   EXPECT_FALSE(context_->registry().HasEntry(kId)); | 
|  | 807 } | 
|  | 808 | 
|  | 809 TEST_F(BlobDispatcherHostTest, CreateBlobWithBrokenReference) { | 
|  | 810   const std::string kBrokenId("id1"); | 
|  | 811   const std::string kReferencingId("id2"); | 
|  | 812 | 
|  | 813   // First, let's test a circular reference. | 
|  | 814   const std::string kCircularId("id1"); | 
|  | 815   host_->OnRegisterBlobUUID(kCircularId, std::string(kContentType), | 
|  | 816                             std::string(kContentDisposition), {kCircularId}); | 
|  | 817   ExpectAndResetBadMessage(); | 
|  | 818 | 
|  | 819   // Next, test a blob that references a broken blob. | 
|  | 820   host_->OnRegisterBlobUUID(kBrokenId, std::string(kContentType), | 
|  | 821                             std::string(kContentDisposition), | 
|  | 822                             std::set<std::string>()); | 
|  | 823   host_->OnCancelBuildingBlob(kBrokenId, IPCBlobCreationCancelCode::UNKNOWN); | 
|  | 824   EXPECT_FALSE(host_->shutdown_for_bad_message_); | 
|  | 825   EXPECT_TRUE(context_->GetBlobDataFromUUID(kBrokenId)->IsBroken()); | 
|  | 826 | 
|  | 827   // Create referencing blob. We should be broken right away, but also ignore | 
|  | 828   // the subsequent OnStart message. | 
|  | 829   host_->OnRegisterBlobUUID(kReferencingId, std::string(kContentType), | 
|  | 830                             std::string(kContentDisposition), {kBrokenId}); | 
|  | 831   EXPECT_TRUE(context_->GetBlobDataFromUUID(kReferencingId)->IsBroken()); | 
|  | 832   EXPECT_FALSE(IsBeingBuiltInHost(kReferencingId)); | 
|  | 833   EXPECT_TRUE(context_->registry().HasEntry(kReferencingId)); | 
|  | 834   ExpectCancel(kReferencingId, | 
|  | 835                IPCBlobCreationCancelCode::REFERENCED_BLOB_BROKEN); | 
|  | 836   sink_.ClearMessages(); | 
|  | 837 | 
|  | 838   DataElement element; | 
|  | 839   element.SetToBytesDescription(kDataSize); | 
|  | 840   std::vector<DataElement> elements = {element}; | 
|  | 841   element.SetToBlob(kBrokenId); | 
|  | 842   elements.push_back(element); | 
|  | 843   host_->OnStartBuildingBlob(kReferencingId, elements); | 
|  | 844   EXPECT_EQ(0u, sink_.message_count()); | 
|  | 845   base::RunLoop().RunUntilIdle(); | 
|  | 846 } | 
|  | 847 | 
|  | 848 TEST_F(BlobDispatcherHostTest, DeferenceBlobOnDifferentHost) { | 
|  | 849   const std::string kId("id"); | 
|  | 850   // Data elements for our transfer & checking messages. | 
|  | 851   DataElement element; | 
|  | 852   element.SetToBytesDescription(kDataSize); | 
|  | 853   std::vector<DataElement> elements = {element}; | 
|  | 854   std::vector<BlobItemBytesRequest> expected_requests = { | 
|  | 855       BlobItemBytesRequest::CreateIPCRequest(0, 0, 0, kDataSize)}; | 
|  | 856   BlobItemBytesResponse response(0); | 
|  | 857   std::memcpy(response.allocate_mutable_data(kDataSize), kData, kDataSize); | 
|  | 858   std::vector<BlobItemBytesResponse> responses = {response}; | 
|  | 859 | 
|  | 860   scoped_refptr<TestableBlobDispatcherHost> host2( | 
|  | 861       new TestableBlobDispatcherHost(chrome_blob_storage_context_, &sink_)); | 
|  | 862 | 
|  | 863   // Delete host with another host having a referencing, then dereference on | 
|  | 864   // second host. Verify we're still building it on first host, and then | 
|  | 865   // verify that a building message from the renderer will kill it. | 
|  | 866 | 
|  | 867   // Test OnStartBuilding after double dereference. | 
|  | 868   host_->OnRegisterBlobUUID(kId, std::string(kContentType), | 
|  | 869                             std::string(kContentDisposition), | 
|  | 870                             std::set<std::string>()); | 
|  | 871   host2->OnIncrementBlobRefCount(kId); | 
|  | 872   host_->OnDecrementBlobRefCount(kId); | 
|  | 873   EXPECT_FALSE(host_->IsInUseInHost(kId)); | 
|  | 874   host2->OnDecrementBlobRefCount(kId); | 
|  | 875   // So no more blob in the context, but we're still being built in host 1. | 
|  | 876   EXPECT_FALSE(context_->registry().HasEntry(kId)); | 
|  | 877   EXPECT_TRUE(host_->async_builder_.IsBeingBuilt(kId)); | 
|  | 878   host_->OnStartBuildingBlob(kId, elements); | 
|  | 879   EXPECT_FALSE(host_->shutdown_for_bad_message_); | 
|  | 880   // We should be cleaned up. | 
|  | 881   EXPECT_FALSE(host_->async_builder_.IsBeingBuilt(kId)); | 
|  | 882   ExpectCancel(kId, | 
|  | 883                IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING); | 
|  | 884   sink_.ClearMessages(); | 
|  | 885 | 
|  | 886   // Same as above, but test OnMemoryItemResponse after double dereference. | 
|  | 887   host_->OnRegisterBlobUUID(kId, std::string(kContentType), | 
|  | 888                             std::string(kContentDisposition), | 
|  | 889                             std::set<std::string>()); | 
|  | 890   host2->OnIncrementBlobRefCount(kId); | 
|  | 891   host_->OnDecrementBlobRefCount(kId); | 
|  | 892   EXPECT_FALSE(host_->IsInUseInHost(kId)); | 
|  | 893   host_->OnStartBuildingBlob(kId, elements); | 
|  | 894   ExpectRequest(kId, expected_requests); | 
|  | 895   sink_.ClearMessages(); | 
|  | 896 | 
|  | 897   host2->OnDecrementBlobRefCount(kId); | 
|  | 898   // So no more blob in the context, but we're still being built in host 1. | 
|  | 899   EXPECT_FALSE(context_->registry().HasEntry(kId)); | 
|  | 900   EXPECT_TRUE(host_->async_builder_.IsBeingBuilt(kId)); | 
|  | 901   host_->OnMemoryItemResponse(kId, responses); | 
|  | 902   EXPECT_FALSE(host_->shutdown_for_bad_message_); | 
|  | 903   // We should be cleaned up. | 
|  | 904   EXPECT_FALSE(host_->async_builder_.IsBeingBuilt(kId)); | 
|  | 905   ExpectCancel(kId, | 
|  | 906                IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING); | 
|  | 907   sink_.ClearMessages(); | 
|  | 908 | 
|  | 909   // Same, but now for OnCancel. | 
|  | 910   host_->OnRegisterBlobUUID(kId, std::string(kContentType), | 
|  | 911                             std::string(kContentDisposition), | 
|  | 912                             std::set<std::string>()); | 
|  | 913   host2->OnIncrementBlobRefCount(kId); | 
|  | 914   host_->OnDecrementBlobRefCount(kId); | 
|  | 915   EXPECT_FALSE(host_->IsInUseInHost(kId)); | 
|  | 916   host_->OnStartBuildingBlob(kId, elements); | 
|  | 917   ExpectRequest(kId, expected_requests); | 
|  | 918   sink_.ClearMessages(); | 
|  | 919 | 
|  | 920   host2->OnDecrementBlobRefCount(kId); | 
|  | 921   // So no more blob in the context, but we're still being built in host 1. | 
|  | 922   EXPECT_FALSE(context_->registry().HasEntry(kId)); | 
|  | 923   EXPECT_TRUE(host_->async_builder_.IsBeingBuilt(kId)); | 
|  | 924   host_->OnCancelBuildingBlob(kId, IPCBlobCreationCancelCode::UNKNOWN); | 
|  | 925   EXPECT_FALSE(host_->shutdown_for_bad_message_); | 
|  | 926   // We should be cleaned up. | 
|  | 927   EXPECT_FALSE(host_->async_builder_.IsBeingBuilt(kId)); | 
|  | 928 } | 
|  | 929 | 
|  | 930 }  // namespace content | 
| OLD | NEW | 
|---|