1 // Copyright (c) 2012 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 // This file contains download browser tests that are known to be runnable 6 // in a pure content context. Over time tests should be migrated here. 7 8 #include "base/command_line.h" 9 #include "base/file_util.h" 10 #include "base/files/file_path.h" 11 #include "base/files/scoped_temp_dir.h" 12 #include "base/strings/stringprintf.h" 13 #include "base/strings/utf_string_conversions.h" 14 #include "content/browser/byte_stream.h" 15 #include "content/browser/download/download_file_factory.h" 16 #include "content/browser/download/download_file_impl.h" 17 #include "content/browser/download/download_item_impl.h" 18 #include "content/browser/download/download_manager_impl.h" 19 #include "content/browser/download/download_resource_handler.h" 20 #include "content/browser/plugin_service_impl.h" 21 #include "content/browser/web_contents/web_contents_impl.h" 22 #include "content/public/browser/power_save_blocker.h" 23 #include "content/public/common/content_switches.h" 24 #include "content/public/common/webplugininfo.h" 25 #include "content/public/test/browser_test_utils.h" 26 #include "content/public/test/download_test_observer.h" 27 #include "content/public/test/test_file_error_injector.h" 28 #include "content/public/test/test_utils.h" 29 #include "content/shell/browser/shell.h" 30 #include "content/shell/browser/shell_browser_context.h" 31 #include "content/shell/browser/shell_download_manager_delegate.h" 32 #include "content/shell/browser/shell_network_delegate.h" 33 #include "content/test/content_browser_test.h" 34 #include "content/test/content_browser_test_utils.h" 35 #include "content/test/net/url_request_mock_http_job.h" 36 #include "content/test/net/url_request_slow_download_job.h" 37 #include "net/test/spawned_test_server/spawned_test_server.h" 38 #include "testing/gmock/include/gmock/gmock.h" 39 #include "testing/gtest/include/gtest/gtest.h" 40 #include "url/gurl.h" 41 42 using ::testing::_; 43 using ::testing::AllOf; 44 using ::testing::Field; 45 using ::testing::InSequence; 46 using ::testing::Property; 47 using ::testing::Return; 48 using ::testing::StrictMock; 49 50 namespace content { 51 52 namespace { 53 54 class MockDownloadItemObserver : public DownloadItem::Observer { 55 public: 56 MockDownloadItemObserver() {} 57 virtual ~MockDownloadItemObserver() {} 58 59 MOCK_METHOD1(OnDownloadUpdated, void(DownloadItem*)); 60 MOCK_METHOD1(OnDownloadOpened, void(DownloadItem*)); 61 MOCK_METHOD1(OnDownloadRemoved, void(DownloadItem*)); 62 MOCK_METHOD1(OnDownloadDestroyed, void(DownloadItem*)); 63 }; 64 65 class MockDownloadManagerObserver : public DownloadManager::Observer { 66 public: 67 MockDownloadManagerObserver(DownloadManager* manager) { 68 manager_ = manager; 69 manager->AddObserver(this); 70 } 71 virtual ~MockDownloadManagerObserver() { 72 if (manager_) 73 manager_->RemoveObserver(this); 74 } 75 76 MOCK_METHOD2(OnDownloadCreated, void(DownloadManager*, DownloadItem*)); 77 MOCK_METHOD1(ModelChanged, void(DownloadManager*)); 78 void ManagerGoingDown(DownloadManager* manager) { 79 DCHECK_EQ(manager_, manager); 80 MockManagerGoingDown(manager); 81 82 manager_->RemoveObserver(this); 83 manager_ = NULL; 84 } 85 86 MOCK_METHOD1(MockManagerGoingDown, void(DownloadManager*)); 87 private: 88 DownloadManager* manager_; 89 }; 90 91 class DownloadFileWithDelayFactory; 92 93 static DownloadManagerImpl* DownloadManagerForShell(Shell* shell) { 94 // We're in a content_browsertest; we know that the DownloadManager 95 // is a DownloadManagerImpl. 96 return static_cast<DownloadManagerImpl*>( 97 BrowserContext::GetDownloadManager( 98 shell->web_contents()->GetBrowserContext())); 99 } 100 101 class DownloadFileWithDelay : public DownloadFileImpl { 102 public: 103 DownloadFileWithDelay( 104 scoped_ptr<DownloadSaveInfo> save_info, 105 const base::FilePath& default_download_directory, 106 const GURL& url, 107 const GURL& referrer_url, 108 bool calculate_hash, 109 scoped_ptr<ByteStreamReader> stream, 110 const net::BoundNetLog& bound_net_log, 111 scoped_ptr<PowerSaveBlocker> power_save_blocker, 112 base::WeakPtr<DownloadDestinationObserver> observer, 113 base::WeakPtr<DownloadFileWithDelayFactory> owner); 114 115 virtual ~DownloadFileWithDelay(); 116 117 // Wraps DownloadFileImpl::Rename* and intercepts the return callback, 118 // storing it in the factory that produced this object for later 119 // retrieval. 120 virtual void RenameAndUniquify( 121 const base::FilePath& full_path, 122 const RenameCompletionCallback& callback) OVERRIDE; 123 virtual void RenameAndAnnotate( 124 const base::FilePath& full_path, 125 const RenameCompletionCallback& callback) OVERRIDE; 126 127 private: 128 static void RenameCallbackWrapper( 129 const base::WeakPtr<DownloadFileWithDelayFactory>& factory, 130 const RenameCompletionCallback& original_callback, 131 DownloadInterruptReason reason, 132 const base::FilePath& path); 133 134 // This variable may only be read on the FILE thread, and may only be 135 // indirected through (e.g. methods on DownloadFileWithDelayFactory called) 136 // on the UI thread. This is because after construction, 137 // DownloadFileWithDelay lives on the file thread, but 138 // DownloadFileWithDelayFactory is purely a UI thread object. 139 base::WeakPtr<DownloadFileWithDelayFactory> owner_; 140 141 DISALLOW_COPY_AND_ASSIGN(DownloadFileWithDelay); 142 }; 143 144 // All routines on this class must be called on the UI thread. 145 class DownloadFileWithDelayFactory : public DownloadFileFactory { 146 public: 147 DownloadFileWithDelayFactory(); 148 virtual ~DownloadFileWithDelayFactory(); 149 150 // DownloadFileFactory interface. 151 virtual DownloadFile* CreateFile( 152 scoped_ptr<DownloadSaveInfo> save_info, 153 const base::FilePath& default_download_directory, 154 const GURL& url, 155 const GURL& referrer_url, 156 bool calculate_hash, 157 scoped_ptr<ByteStreamReader> stream, 158 const net::BoundNetLog& bound_net_log, 159 base::WeakPtr<DownloadDestinationObserver> observer) OVERRIDE; 160 161 void AddRenameCallback(base::Closure callback); 162 void GetAllRenameCallbacks(std::vector<base::Closure>* results); 163 164 // Do not return until GetAllRenameCallbacks() will return a non-empty list. 165 void WaitForSomeCallback(); 166 167 private: 168 base::WeakPtrFactory<DownloadFileWithDelayFactory> weak_ptr_factory_; 169 std::vector<base::Closure> rename_callbacks_; 170 bool waiting_; 171 172 DISALLOW_COPY_AND_ASSIGN(DownloadFileWithDelayFactory); 173 }; 174 175 DownloadFileWithDelay::DownloadFileWithDelay( 176 scoped_ptr<DownloadSaveInfo> save_info, 177 const base::FilePath& default_download_directory, 178 const GURL& url, 179 const GURL& referrer_url, 180 bool calculate_hash, 181 scoped_ptr<ByteStreamReader> stream, 182 const net::BoundNetLog& bound_net_log, 183 scoped_ptr<PowerSaveBlocker> power_save_blocker, 184 base::WeakPtr<DownloadDestinationObserver> observer, 185 base::WeakPtr<DownloadFileWithDelayFactory> owner) 186 : DownloadFileImpl( 187 save_info.Pass(), default_download_directory, url, referrer_url, 188 calculate_hash, stream.Pass(), bound_net_log, 189 power_save_blocker.Pass(), observer), 190 owner_(owner) {} 191 192 DownloadFileWithDelay::~DownloadFileWithDelay() {} 193 194 void DownloadFileWithDelay::RenameAndUniquify( 195 const base::FilePath& full_path, 196 const RenameCompletionCallback& callback) { 197 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 198 DownloadFileImpl::RenameAndUniquify( 199 full_path, base::Bind(DownloadFileWithDelay::RenameCallbackWrapper, 200 owner_, callback)); 201 } 202 203 void DownloadFileWithDelay::RenameAndAnnotate( 204 const base::FilePath& full_path, const RenameCompletionCallback& callback) { 205 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 206 DownloadFileImpl::RenameAndAnnotate( 207 full_path, base::Bind(DownloadFileWithDelay::RenameCallbackWrapper, 208 owner_, callback)); 209 } 210 211 // static 212 void DownloadFileWithDelay::RenameCallbackWrapper( 213 const base::WeakPtr<DownloadFileWithDelayFactory>& factory, 214 const RenameCompletionCallback& original_callback, 215 DownloadInterruptReason reason, 216 const base::FilePath& path) { 217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 218 if (!factory) 219 return; 220 factory->AddRenameCallback(base::Bind(original_callback, reason, path)); 221 } 222 223 DownloadFileWithDelayFactory::DownloadFileWithDelayFactory() 224 : weak_ptr_factory_(this), 225 waiting_(false) {} 226 DownloadFileWithDelayFactory::~DownloadFileWithDelayFactory() {} 227 228 DownloadFile* DownloadFileWithDelayFactory::CreateFile( 229 scoped_ptr<DownloadSaveInfo> save_info, 230 const base::FilePath& default_download_directory, 231 const GURL& url, 232 const GURL& referrer_url, 233 bool calculate_hash, 234 scoped_ptr<ByteStreamReader> stream, 235 const net::BoundNetLog& bound_net_log, 236 base::WeakPtr<DownloadDestinationObserver> observer) { 237 scoped_ptr<PowerSaveBlocker> psb( 238 PowerSaveBlocker::Create( 239 PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension, 240 "Download in progress")); 241 return new DownloadFileWithDelay( 242 save_info.Pass(), default_download_directory, url, referrer_url, 243 calculate_hash, stream.Pass(), bound_net_log, 244 psb.Pass(), observer, weak_ptr_factory_.GetWeakPtr()); 245 } 246 247 void DownloadFileWithDelayFactory::AddRenameCallback(base::Closure callback) { 248 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 249 rename_callbacks_.push_back(callback); 250 if (waiting_) 251 base::MessageLoopForUI::current()->Quit(); 252 } 253 254 void DownloadFileWithDelayFactory::GetAllRenameCallbacks( 255 std::vector<base::Closure>* results) { 256 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 257 results->swap(rename_callbacks_); 258 } 259 260 void DownloadFileWithDelayFactory::WaitForSomeCallback() { 261 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 262 263 if (rename_callbacks_.empty()) { 264 waiting_ = true; 265 RunMessageLoop(); 266 waiting_ = false; 267 } 268 } 269 270 class CountingDownloadFile : public DownloadFileImpl { 271 public: 272 CountingDownloadFile( 273 scoped_ptr<DownloadSaveInfo> save_info, 274 const base::FilePath& default_downloads_directory, 275 const GURL& url, 276 const GURL& referrer_url, 277 bool calculate_hash, 278 scoped_ptr<ByteStreamReader> stream, 279 const net::BoundNetLog& bound_net_log, 280 scoped_ptr<PowerSaveBlocker> power_save_blocker, 281 base::WeakPtr<DownloadDestinationObserver> observer) 282 : DownloadFileImpl(save_info.Pass(), default_downloads_directory, 283 url, referrer_url, calculate_hash, 284 stream.Pass(), bound_net_log, 285 power_save_blocker.Pass(), observer) {} 286 287 virtual ~CountingDownloadFile() { 288 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 289 active_files_--; 290 } 291 292 virtual void Initialize(const InitializeCallback& callback) OVERRIDE { 293 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 294 active_files_++; 295 return DownloadFileImpl::Initialize(callback); 296 } 297 298 static void GetNumberActiveFiles(int* result) { 299 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 300 *result = active_files_; 301 } 302 303 // Can be called on any thread, and will block (running message loop) 304 // until data is returned. 305 static int GetNumberActiveFilesFromFileThread() { 306 int result = -1; 307 BrowserThread::PostTaskAndReply( 308 BrowserThread::FILE, 309 FROM_HERE, 310 base::Bind(&CountingDownloadFile::GetNumberActiveFiles, &result), 311 base::MessageLoop::current()->QuitClosure()); 312 base::MessageLoop::current()->Run(); 313 DCHECK_NE(-1, result); 314 return result; 315 } 316 317 private: 318 static int active_files_; 319 }; 320 321 int CountingDownloadFile::active_files_ = 0; 322 323 class CountingDownloadFileFactory : public DownloadFileFactory { 324 public: 325 CountingDownloadFileFactory() {} 326 virtual ~CountingDownloadFileFactory() {} 327 328 // DownloadFileFactory interface. 329 virtual DownloadFile* CreateFile( 330 scoped_ptr<DownloadSaveInfo> save_info, 331 const base::FilePath& default_downloads_directory, 332 const GURL& url, 333 const GURL& referrer_url, 334 bool calculate_hash, 335 scoped_ptr<ByteStreamReader> stream, 336 const net::BoundNetLog& bound_net_log, 337 base::WeakPtr<DownloadDestinationObserver> observer) OVERRIDE { 338 scoped_ptr<PowerSaveBlocker> psb( 339 PowerSaveBlocker::Create( 340 PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension, 341 "Download in progress")); 342 return new CountingDownloadFile( 343 save_info.Pass(), default_downloads_directory, url, referrer_url, 344 calculate_hash, stream.Pass(), bound_net_log, 345 psb.Pass(), observer); 346 } 347 }; 348 349 class TestShellDownloadManagerDelegate : public ShellDownloadManagerDelegate { 350 public: 351 TestShellDownloadManagerDelegate() 352 : delay_download_open_(false) {} 353 354 virtual bool ShouldOpenDownload( 355 DownloadItem* item, 356 const DownloadOpenDelayedCallback& callback) OVERRIDE { 357 if (delay_download_open_) { 358 delayed_callbacks_.push_back(callback); 359 return false; 360 } 361 return true; 362 } 363 364 void SetDelayedOpen(bool delay) { 365 delay_download_open_ = delay; 366 } 367 368 void GetDelayedCallbacks( 369 std::vector<DownloadOpenDelayedCallback>* callbacks) { 370 callbacks->swap(delayed_callbacks_); 371 } 372 private: 373 virtual ~TestShellDownloadManagerDelegate() {} 374 375 bool delay_download_open_; 376 std::vector<DownloadOpenDelayedCallback> delayed_callbacks_; 377 }; 378 379 // Record all state transitions and byte counts on the observed download. 380 class RecordingDownloadObserver : DownloadItem::Observer { 381 public: 382 struct RecordStruct { 383 DownloadItem::DownloadState state; 384 int bytes_received; 385 }; 386 387 typedef std::vector<RecordStruct> RecordVector; 388 389 RecordingDownloadObserver(DownloadItem* download) 390 : download_(download) { 391 last_state_.state = download->GetState(); 392 last_state_.bytes_received = download->GetReceivedBytes(); 393 download_->AddObserver(this); 394 } 395 396 virtual ~RecordingDownloadObserver() { 397 RemoveObserver(); 398 } 399 400 void CompareToExpectedRecord(const RecordStruct expected[], size_t size) { 401 EXPECT_EQ(size, record_.size()); 402 int min = size > record_.size() ? record_.size() : size; 403 for (int i = 0; i < min; ++i) { 404 EXPECT_EQ(expected[i].state, record_[i].state) << "Iteration " << i; 405 EXPECT_EQ(expected[i].bytes_received, record_[i].bytes_received) 406 << "Iteration " << i; 407 } 408 } 409 410 private: 411 virtual void OnDownloadUpdated(DownloadItem* download) OVERRIDE { 412 DCHECK_EQ(download_, download); 413 DownloadItem::DownloadState state = download->GetState(); 414 int bytes = download->GetReceivedBytes(); 415 if (last_state_.state != state || last_state_.bytes_received > bytes) { 416 last_state_.state = state; 417 last_state_.bytes_received = bytes; 418 record_.push_back(last_state_); 419 } 420 } 421 422 virtual void OnDownloadDestroyed(DownloadItem* download) OVERRIDE { 423 DCHECK_EQ(download_, download); 424 RemoveObserver(); 425 } 426 427 void RemoveObserver() { 428 if (download_) { 429 download_->RemoveObserver(this); 430 download_ = NULL; 431 } 432 } 433 434 DownloadItem* download_; 435 RecordStruct last_state_; 436 RecordVector record_; 437 }; 438 439 // Get the next created download. 440 class DownloadCreateObserver : DownloadManager::Observer { 441 public: 442 DownloadCreateObserver(DownloadManager* manager) 443 : manager_(manager), 444 item_(NULL), 445 waiting_(false) { 446 manager_->AddObserver(this); 447 } 448 449 virtual ~DownloadCreateObserver() { 450 if (manager_) 451 manager_->RemoveObserver(this); 452 manager_ = NULL; 453 } 454 455 virtual void ManagerGoingDown(DownloadManager* manager) OVERRIDE { 456 DCHECK_EQ(manager_, manager); 457 manager_->RemoveObserver(this); 458 manager_ = NULL; 459 } 460 461 virtual void OnDownloadCreated(DownloadManager* manager, 462 DownloadItem* download) OVERRIDE { 463 if (!item_) 464 item_ = download; 465 466 if (waiting_) 467 base::MessageLoopForUI::current()->Quit(); 468 } 469 470 DownloadItem* WaitForFinished() { 471 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 472 if (!item_) { 473 waiting_ = true; 474 RunMessageLoop(); 475 waiting_ = false; 476 } 477 return item_; 478 } 479 480 private: 481 DownloadManager* manager_; 482 DownloadItem* item_; 483 bool waiting_; 484 }; 485 486 487 // Filter for waiting for a certain number of bytes. 488 bool DataReceivedFilter(int number_of_bytes, DownloadItem* download) { 489 return download->GetReceivedBytes() >= number_of_bytes; 490 } 491 492 // Filter for download completion. 493 bool DownloadCompleteFilter(DownloadItem* download) { 494 return download->GetState() == DownloadItem::COMPLETE; 495 } 496 497 // Filter for saving the size of the download when the first IN_PROGRESS 498 // is hit. 499 bool InitialSizeFilter(int* download_size, DownloadItem* download) { 500 if (download->GetState() != DownloadItem::IN_PROGRESS) 501 return false; 502 503 *download_size = download->GetReceivedBytes(); 504 return true; 505 } 506 507 } // namespace 508 509 class DownloadContentTest : public ContentBrowserTest { 510 protected: 511 // An initial send from a website of at least this size will not be 512 // help up by buffering in the underlying downloads ByteStream data 513 // transfer. This is important because on resumption tests we wait 514 // until we've gotten the data we expect before allowing the test server 515 // to send its reset, to get around hard close semantics on the Windows 516 // socket layer implementation. 517 int GetSafeBufferChunk() const { 518 return (DownloadResourceHandler::kDownloadByteStreamSize / 519 ByteStreamWriter::kFractionBufferBeforeSending) + 1; 520 } 521 522 virtual void SetUpOnMainThread() OVERRIDE { 523 ASSERT_TRUE(downloads_directory_.CreateUniqueTempDir()); 524 525 TestShellDownloadManagerDelegate* delegate = 526 new TestShellDownloadManagerDelegate(); 527 delegate->SetDownloadBehaviorForTesting(downloads_directory_.path()); 528 DownloadManager* manager = DownloadManagerForShell(shell()); 529 manager->SetDelegate(delegate); 530 delegate->SetDownloadManager(manager); 531 532 BrowserThread::PostTask( 533 BrowserThread::IO, FROM_HERE, 534 base::Bind(&URLRequestSlowDownloadJob::AddUrlHandler)); 535 base::FilePath mock_base(GetTestFilePath("download", "")); 536 BrowserThread::PostTask( 537 BrowserThread::IO, FROM_HERE, 538 base::Bind(&URLRequestMockHTTPJob::AddUrlHandler, mock_base)); 539 } 540 541 TestShellDownloadManagerDelegate* GetDownloadManagerDelegate( 542 DownloadManager* manager) { 543 return static_cast<TestShellDownloadManagerDelegate*>( 544 manager->GetDelegate()); 545 } 546 547 // Create a DownloadTestObserverTerminal that will wait for the 548 // specified number of downloads to finish. 549 DownloadTestObserver* CreateWaiter( 550 Shell* shell, int num_downloads) { 551 DownloadManager* download_manager = DownloadManagerForShell(shell); 552 return new DownloadTestObserverTerminal(download_manager, num_downloads, 553 DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL); 554 } 555 556 // Create a DownloadTestObserverInProgress that will wait for the 557 // specified number of downloads to start. 558 DownloadCreateObserver* CreateInProgressWaiter( 559 Shell* shell, int num_downloads) { 560 DownloadManager* download_manager = DownloadManagerForShell(shell); 561 return new DownloadCreateObserver(download_manager); 562 } 563 564 DownloadTestObserver* CreateInterruptedWaiter( 565 Shell* shell, int num_downloads) { 566 DownloadManager* download_manager = DownloadManagerForShell(shell); 567 return new DownloadTestObserverInterrupted(download_manager, num_downloads, 568 DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL); 569 } 570 571 // Note: Cannot be used with other alternative DownloadFileFactorys 572 void SetupEnsureNoPendingDownloads() { 573 DownloadManagerForShell(shell())->SetDownloadFileFactoryForTesting( 574 scoped_ptr<DownloadFileFactory>( 575 new CountingDownloadFileFactory()).Pass()); 576 } 577 578 bool EnsureNoPendingDownloads() { 579 bool result = true; 580 BrowserThread::PostTask( 581 BrowserThread::IO, FROM_HERE, 582 base::Bind(&EnsureNoPendingDownloadJobsOnIO, &result)); 583 base::MessageLoop::current()->Run(); 584 return result && 585 (CountingDownloadFile::GetNumberActiveFilesFromFileThread() == 0); 586 } 587 588 void DownloadAndWait(Shell* shell, const GURL& url, 589 DownloadItem::DownloadState expected_terminal_state) { 590 scoped_ptr<DownloadTestObserver> observer(CreateWaiter(shell, 1)); 591 NavigateToURL(shell, url); 592 observer->WaitForFinished(); 593 EXPECT_EQ(1u, observer->NumDownloadsSeenInState(expected_terminal_state)); 594 } 595 596 // Checks that |path| is has |file_size| bytes, and matches the |value| 597 // string. 598 bool VerifyFile(const base::FilePath& path, 599 const std::string& value, 600 const int64 file_size) { 601 std::string file_contents; 602 603 bool read = base::ReadFileToString(path, &file_contents); 604 EXPECT_TRUE(read) << "Failed reading file: " << path.value() << std::endl; 605 if (!read) 606 return false; // Couldn't read the file. 607 608 // Note: we don't handle really large files (more than size_t can hold) 609 // so we will fail in that case. 610 size_t expected_size = static_cast<size_t>(file_size); 611 612 // Check the size. 613 EXPECT_EQ(expected_size, file_contents.size()); 614 if (expected_size != file_contents.size()) 615 return false; 616 617 // Check the contents. 618 EXPECT_EQ(value, file_contents); 619 if (memcmp(file_contents.c_str(), value.c_str(), expected_size) != 0) 620 return false; 621 622 return true; 623 } 624 625 // Start a download and return the item. 626 DownloadItem* StartDownloadAndReturnItem(GURL url) { 627 scoped_ptr<DownloadCreateObserver> observer( 628 CreateInProgressWaiter(shell(), 1)); 629 NavigateToURL(shell(), url); 630 observer->WaitForFinished(); 631 std::vector<DownloadItem*> downloads; 632 DownloadManagerForShell(shell())->GetAllDownloads(&downloads); 633 EXPECT_EQ(1u, downloads.size()); 634 if (1u != downloads.size()) 635 return NULL; 636 return downloads[0]; 637 } 638 639 // Wait for data 640 void WaitForData(DownloadItem* download, int size) { 641 DownloadUpdatedObserver data_observer( 642 download, base::Bind(&DataReceivedFilter, size)); 643 data_observer.WaitForEvent(); 644 ASSERT_EQ(size, download->GetReceivedBytes()); 645 ASSERT_EQ(DownloadItem::IN_PROGRESS, download->GetState()); 646 } 647 648 // Tell the test server to release a pending RST and confirm 649 // that the interrupt is received properly (for download resumption 650 // testing). 651 void ReleaseRSTAndConfirmInterruptForResume(DownloadItem* download) { 652 scoped_ptr<DownloadTestObserver> rst_observer( 653 CreateInterruptedWaiter(shell(), 1)); 654 NavigateToURL(shell(), test_server()->GetURL("download-finish")); 655 rst_observer->WaitForFinished(); 656 EXPECT_EQ(DownloadItem::INTERRUPTED, download->GetState()); 657 } 658 659 // Confirm file status expected for the given location in a stream 660 // provided by the resume test server. 661 void ConfirmFileStatusForResume( 662 DownloadItem* download, bool file_exists, 663 int received_bytes, int total_bytes, 664 const base::FilePath& expected_filename) { 665 // expected_filename is only known if the file exists. 666 ASSERT_EQ(file_exists, !expected_filename.empty()); 667 EXPECT_EQ(received_bytes, download->GetReceivedBytes()); 668 EXPECT_EQ(total_bytes, download->GetTotalBytes()); 669 EXPECT_EQ(expected_filename.value(), 670 download->GetFullPath().BaseName().value()); 671 EXPECT_EQ(file_exists, 672 (!download->GetFullPath().empty() && 673 base::PathExists(download->GetFullPath()))); 674 675 if (file_exists) { 676 std::string file_contents; 677 EXPECT_TRUE(base::ReadFileToString( 678 download->GetFullPath(), &file_contents)); 679 680 ASSERT_EQ(static_cast<size_t>(received_bytes), file_contents.size()); 681 for (int i = 0; i < received_bytes; ++i) { 682 EXPECT_EQ(static_cast<char>((i * 2 + 15) % 256), file_contents[i]) 683 << "File contents diverged at position " << i 684 << " for " << expected_filename.value(); 685 686 if (static_cast<char>((i * 2 + 15) % 256) != file_contents[i]) 687 return; 688 } 689 } 690 } 691 692 private: 693 static void EnsureNoPendingDownloadJobsOnIO(bool* result) { 694 if (URLRequestSlowDownloadJob::NumberOutstandingRequests()) 695 *result = false; 696 BrowserThread::PostTask( 697 BrowserThread::UI, FROM_HERE, base::MessageLoop::QuitClosure()); 698 } 699 700 // Location of the downloads directory for these tests 701 base::ScopedTempDir downloads_directory_; 702 }; 703 704 IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadCancelled) { 705 SetupEnsureNoPendingDownloads(); 706 707 // Create a download, wait until it's started, and confirm 708 // we're in the expected state. 709 scoped_ptr<DownloadCreateObserver> observer( 710 CreateInProgressWaiter(shell(), 1)); 711 NavigateToURL(shell(), GURL(URLRequestSlowDownloadJob::kUnknownSizeUrl)); 712 observer->WaitForFinished(); 713 714 std::vector<DownloadItem*> downloads; 715 DownloadManagerForShell(shell())->GetAllDownloads(&downloads); 716 ASSERT_EQ(1u, downloads.size()); 717 ASSERT_EQ(DownloadItem::IN_PROGRESS, downloads[0]->GetState()); 718 719 // Cancel the download and wait for download system quiesce. 720 downloads[0]->Cancel(true); 721 scoped_refptr<DownloadTestFlushObserver> flush_observer( 722 new DownloadTestFlushObserver(DownloadManagerForShell(shell()))); 723 flush_observer->WaitForFlush(); 724 725 // Get the important info from other threads and check it. 726 EXPECT_TRUE(EnsureNoPendingDownloads()); 727 } 728 729 // Check that downloading multiple (in this case, 2) files does not result in 730 // corrupted files. 731 IN_PROC_BROWSER_TEST_F(DownloadContentTest, MultiDownload) { 732 SetupEnsureNoPendingDownloads(); 733 734 // Create a download, wait until it's started, and confirm 735 // we're in the expected state. 736 scoped_ptr<DownloadCreateObserver> observer1( 737 CreateInProgressWaiter(shell(), 1)); 738 NavigateToURL(shell(), GURL(URLRequestSlowDownloadJob::kUnknownSizeUrl)); 739 observer1->WaitForFinished(); 740 741 std::vector<DownloadItem*> downloads; 742 DownloadManagerForShell(shell())->GetAllDownloads(&downloads); 743 ASSERT_EQ(1u, downloads.size()); 744 ASSERT_EQ(DownloadItem::IN_PROGRESS, downloads[0]->GetState()); 745 DownloadItem* download1 = downloads[0]; // The only download. 746 747 // Start the second download and wait until it's done. 748 base::FilePath file(FILE_PATH_LITERAL("download-test.lib")); 749 GURL url(URLRequestMockHTTPJob::GetMockUrl(file)); 750 // Download the file and wait. 751 DownloadAndWait(shell(), url, DownloadItem::COMPLETE); 752 753 // Should now have 2 items on the manager. 754 downloads.clear(); 755 DownloadManagerForShell(shell())->GetAllDownloads(&downloads); 756 ASSERT_EQ(2u, downloads.size()); 757 // We don't know the order of the downloads. 758 DownloadItem* download2 = downloads[(download1 == downloads[0]) ? 1 : 0]; 759 760 ASSERT_EQ(DownloadItem::IN_PROGRESS, download1->GetState()); 761 ASSERT_EQ(DownloadItem::COMPLETE, download2->GetState()); 762 763 // Allow the first request to finish. 764 scoped_ptr<DownloadTestObserver> observer2(CreateWaiter(shell(), 1)); 765 NavigateToURL(shell(), GURL(URLRequestSlowDownloadJob::kFinishDownloadUrl)); 766 observer2->WaitForFinished(); // Wait for the third request. 767 EXPECT_EQ(1u, observer2->NumDownloadsSeenInState(DownloadItem::COMPLETE)); 768 769 // Get the important info from other threads and check it. 770 EXPECT_TRUE(EnsureNoPendingDownloads()); 771 772 // The |DownloadItem|s should now be done and have the final file names. 773 // Verify that the files have the expected data and size. 774 // |file1| should be full of '*'s, and |file2| should be the same as the 775 // source file. 776 base::FilePath file1(download1->GetTargetFilePath()); 777 size_t file_size1 = URLRequestSlowDownloadJob::kFirstDownloadSize + 778 URLRequestSlowDownloadJob::kSecondDownloadSize; 779 std::string expected_contents(file_size1, '*'); 780 ASSERT_TRUE(VerifyFile(file1, expected_contents, file_size1)); 781 782 base::FilePath file2(download2->GetTargetFilePath()); 783 ASSERT_TRUE(base::ContentsEqual( 784 file2, GetTestFilePath("download", "download-test.lib"))); 785 } 786 787 #if defined(ENABLE_PLUGINS) 788 // Content served with a MIME type of application/octet-stream should be 789 // downloaded even when a plugin can be found that handles the file type. 790 IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadOctetStream) { 791 const base::FilePath::CharType kTestFilePath[] = 792 FILE_PATH_LITERAL("octet-stream.abc"); 793 const char kTestPluginName[] = "TestPlugin"; 794 const char kTestMimeType[] = "application/x-test-mime-type"; 795 const char kTestFileType[] = "abc"; 796 797 WebPluginInfo plugin_info; 798 plugin_info.name = base::ASCIIToUTF16(kTestPluginName); 799 plugin_info.mime_types.push_back( 800 WebPluginMimeType(kTestMimeType, kTestFileType, "")); 801 PluginServiceImpl::GetInstance()->RegisterInternalPlugin(plugin_info, false); 802 803 // The following is served with a Content-Type of application/octet-stream. 804 GURL url(URLRequestMockHTTPJob::GetMockUrl(base::FilePath(kTestFilePath))); 805 DownloadAndWait(shell(), url, DownloadItem::COMPLETE); 806 } 807 #endif 808 809 // Try to cancel just before we release the download file, by delaying final 810 // rename callback. 811 IN_PROC_BROWSER_TEST_F(DownloadContentTest, CancelAtFinalRename) { 812 // Setup new factory. 813 DownloadFileWithDelayFactory* file_factory = 814 new DownloadFileWithDelayFactory(); 815 DownloadManagerImpl* download_manager(DownloadManagerForShell(shell())); 816 download_manager->SetDownloadFileFactoryForTesting( 817 scoped_ptr<DownloadFileFactory>(file_factory).Pass()); 818 819 // Create a download 820 base::FilePath file(FILE_PATH_LITERAL("download-test.lib")); 821 NavigateToURL(shell(), URLRequestMockHTTPJob::GetMockUrl(file)); 822 823 // Wait until the first (intermediate file) rename and execute the callback. 824 file_factory->WaitForSomeCallback(); 825 std::vector<base::Closure> callbacks; 826 file_factory->GetAllRenameCallbacks(&callbacks); 827 ASSERT_EQ(1u, callbacks.size()); 828 callbacks[0].Run(); 829 callbacks.clear(); 830 831 // Wait until the second (final) rename callback is posted. 832 file_factory->WaitForSomeCallback(); 833 file_factory->GetAllRenameCallbacks(&callbacks); 834 ASSERT_EQ(1u, callbacks.size()); 835 836 // Cancel it. 837 std::vector<DownloadItem*> items; 838 download_manager->GetAllDownloads(&items); 839 ASSERT_EQ(1u, items.size()); 840 items[0]->Cancel(true); 841 RunAllPendingInMessageLoop(); 842 843 // Check state. 844 EXPECT_EQ(DownloadItem::CANCELLED, items[0]->GetState()); 845 846 // Run final rename callback. 847 callbacks[0].Run(); 848 callbacks.clear(); 849 850 // Check state. 851 EXPECT_EQ(DownloadItem::CANCELLED, items[0]->GetState()); 852 } 853 854 // Try to cancel just after we release the download file, by delaying 855 // in ShouldOpenDownload. 856 IN_PROC_BROWSER_TEST_F(DownloadContentTest, CancelAtRelease) { 857 DownloadManagerImpl* download_manager(DownloadManagerForShell(shell())); 858 859 // Mark delegate for delayed open. 860 GetDownloadManagerDelegate(download_manager)->SetDelayedOpen(true); 861 862 // Setup new factory. 863 DownloadFileWithDelayFactory* file_factory = 864 new DownloadFileWithDelayFactory(); 865 download_manager->SetDownloadFileFactoryForTesting( 866 scoped_ptr<DownloadFileFactory>(file_factory).Pass()); 867 868 // Create a download 869 base::FilePath file(FILE_PATH_LITERAL("download-test.lib")); 870 NavigateToURL(shell(), URLRequestMockHTTPJob::GetMockUrl(file)); 871 872 // Wait until the first (intermediate file) rename and execute the callback. 873 file_factory->WaitForSomeCallback(); 874 std::vector<base::Closure> callbacks; 875 file_factory->GetAllRenameCallbacks(&callbacks); 876 ASSERT_EQ(1u, callbacks.size()); 877 callbacks[0].Run(); 878 callbacks.clear(); 879 880 // Wait until the second (final) rename callback is posted. 881 file_factory->WaitForSomeCallback(); 882 file_factory->GetAllRenameCallbacks(&callbacks); 883 ASSERT_EQ(1u, callbacks.size()); 884 885 // Call it. 886 callbacks[0].Run(); 887 callbacks.clear(); 888 889 // Confirm download still IN_PROGRESS (internal state COMPLETING). 890 std::vector<DownloadItem*> items; 891 download_manager->GetAllDownloads(&items); 892 EXPECT_EQ(DownloadItem::IN_PROGRESS, items[0]->GetState()); 893 894 // Cancel the download; confirm cancel fails. 895 ASSERT_EQ(1u, items.size()); 896 items[0]->Cancel(true); 897 EXPECT_EQ(DownloadItem::IN_PROGRESS, items[0]->GetState()); 898 899 // Need to complete open test. 900 std::vector<DownloadOpenDelayedCallback> delayed_callbacks; 901 GetDownloadManagerDelegate(download_manager)->GetDelayedCallbacks( 902 &delayed_callbacks); 903 ASSERT_EQ(1u, delayed_callbacks.size()); 904 delayed_callbacks[0].Run(true); 905 906 // *Now* the download should be complete. 907 EXPECT_EQ(DownloadItem::COMPLETE, items[0]->GetState()); 908 } 909 910 // Try to shutdown with a download in progress to make sure shutdown path 911 // works properly. 912 IN_PROC_BROWSER_TEST_F(DownloadContentTest, ShutdownInProgress) { 913 // Create a download that won't complete. 914 scoped_ptr<DownloadCreateObserver> observer( 915 CreateInProgressWaiter(shell(), 1)); 916 NavigateToURL(shell(), GURL(URLRequestSlowDownloadJob::kUnknownSizeUrl)); 917 observer->WaitForFinished(); 918 919 // Get the item. 920 std::vector<DownloadItem*> items; 921 DownloadManagerForShell(shell())->GetAllDownloads(&items); 922 ASSERT_EQ(1u, items.size()); 923 EXPECT_EQ(DownloadItem::IN_PROGRESS, items[0]->GetState()); 924 925 // Shutdown the download manager and make sure we get the right 926 // notifications in the right order. 927 StrictMock<MockDownloadItemObserver> item_observer; 928 items[0]->AddObserver(&item_observer); 929 MockDownloadManagerObserver manager_observer( 930 DownloadManagerForShell(shell())); 931 // Don't care about ModelChanged() events. 932 EXPECT_CALL(manager_observer, ModelChanged(_)) 933 .WillRepeatedly(Return()); 934 { 935 InSequence notifications; 936 937 EXPECT_CALL(manager_observer, MockManagerGoingDown( 938 DownloadManagerForShell(shell()))) 939 .WillOnce(Return()); 940 EXPECT_CALL(item_observer, OnDownloadUpdated( 941 AllOf(items[0], 942 Property(&DownloadItem::GetState, DownloadItem::CANCELLED)))) 943 .WillOnce(Return()); 944 EXPECT_CALL(item_observer, OnDownloadDestroyed(items[0])) 945 .WillOnce(Return()); 946 } 947 DownloadManagerForShell(shell())->Shutdown(); 948 items.clear(); 949 } 950 951 // Try to shutdown just after we release the download file, by delaying 952 // release. 953 IN_PROC_BROWSER_TEST_F(DownloadContentTest, ShutdownAtRelease) { 954 DownloadManagerImpl* download_manager(DownloadManagerForShell(shell())); 955 956 // Mark delegate for delayed open. 957 GetDownloadManagerDelegate(download_manager)->SetDelayedOpen(true); 958 959 // Setup new factory. 960 DownloadFileWithDelayFactory* file_factory = 961 new DownloadFileWithDelayFactory(); 962 download_manager->SetDownloadFileFactoryForTesting( 963 scoped_ptr<DownloadFileFactory>(file_factory).Pass()); 964 965 // Create a download 966 base::FilePath file(FILE_PATH_LITERAL("download-test.lib")); 967 NavigateToURL(shell(), URLRequestMockHTTPJob::GetMockUrl(file)); 968 969 // Wait until the first (intermediate file) rename and execute the callback. 970 file_factory->WaitForSomeCallback(); 971 std::vector<base::Closure> callbacks; 972 file_factory->GetAllRenameCallbacks(&callbacks); 973 ASSERT_EQ(1u, callbacks.size()); 974 callbacks[0].Run(); 975 callbacks.clear(); 976 977 // Wait until the second (final) rename callback is posted. 978 file_factory->WaitForSomeCallback(); 979 file_factory->GetAllRenameCallbacks(&callbacks); 980 ASSERT_EQ(1u, callbacks.size()); 981 982 // Call it. 983 callbacks[0].Run(); 984 callbacks.clear(); 985 986 // Confirm download isn't complete yet. 987 std::vector<DownloadItem*> items; 988 DownloadManagerForShell(shell())->GetAllDownloads(&items); 989 EXPECT_EQ(DownloadItem::IN_PROGRESS, items[0]->GetState()); 990 991 // Cancel the download; confirm cancel fails anyway. 992 ASSERT_EQ(1u, items.size()); 993 items[0]->Cancel(true); 994 EXPECT_EQ(DownloadItem::IN_PROGRESS, items[0]->GetState()); 995 RunAllPendingInMessageLoop(); 996 EXPECT_EQ(DownloadItem::IN_PROGRESS, items[0]->GetState()); 997 998 MockDownloadItemObserver observer; 999 items[0]->AddObserver(&observer); 1000 EXPECT_CALL(observer, OnDownloadDestroyed(items[0])); 1001 1002 // Shutdown the download manager. Mostly this is confirming a lack of 1003 // crashes. 1004 DownloadManagerForShell(shell())->Shutdown(); 1005 } 1006 1007 IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeInterruptedDownload) { 1008 CommandLine::ForCurrentProcess()->AppendSwitch( 1009 switches::kEnableDownloadResumption); 1010 ASSERT_TRUE(test_server()->Start()); 1011 1012 GURL url = test_server()->GetURL( 1013 base::StringPrintf("rangereset?size=%d&rst_boundary=%d", 1014 GetSafeBufferChunk() * 3, GetSafeBufferChunk())); 1015 1016 MockDownloadManagerObserver dm_observer(DownloadManagerForShell(shell())); 1017 EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(1); 1018 1019 DownloadItem* download(StartDownloadAndReturnItem(url)); 1020 WaitForData(download, GetSafeBufferChunk()); 1021 ::testing::Mock::VerifyAndClearExpectations(&dm_observer); 1022 1023 // Confirm resumption while in progress doesn't do anything. 1024 download->Resume(); 1025 ASSERT_EQ(GetSafeBufferChunk(), download->GetReceivedBytes()); 1026 ASSERT_EQ(DownloadItem::IN_PROGRESS, download->GetState()); 1027 1028 // Tell the server to send the RST and confirm the interrupt happens. 1029 ReleaseRSTAndConfirmInterruptForResume(download); 1030 ConfirmFileStatusForResume( 1031 download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3, 1032 base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload"))); 1033 1034 // Resume, confirming received bytes on resumption is correct. 1035 // Make sure no creation calls are included. 1036 EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(0); 1037 int initial_size = 0; 1038 DownloadUpdatedObserver initial_size_observer( 1039 download, base::Bind(&InitialSizeFilter, &initial_size)); 1040 download->Resume(); 1041 initial_size_observer.WaitForEvent(); 1042 EXPECT_EQ(GetSafeBufferChunk(), initial_size); 1043 ::testing::Mock::VerifyAndClearExpectations(&dm_observer); 1044 1045 // and wait for expected data. 1046 WaitForData(download, GetSafeBufferChunk() * 2); 1047 1048 // Tell the server to send the RST and confirm the interrupt happens. 1049 ReleaseRSTAndConfirmInterruptForResume(download); 1050 ConfirmFileStatusForResume( 1051 download, true, GetSafeBufferChunk() * 2, GetSafeBufferChunk() * 3, 1052 base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload"))); 1053 1054 // Resume and wait for completion. 1055 DownloadUpdatedObserver completion_observer( 1056 download, base::Bind(DownloadCompleteFilter)); 1057 download->Resume(); 1058 completion_observer.WaitForEvent(); 1059 1060 ConfirmFileStatusForResume( 1061 download, true, GetSafeBufferChunk() * 3, GetSafeBufferChunk() * 3, 1062 base::FilePath(FILE_PATH_LITERAL("rangereset"))); 1063 1064 // Confirm resumption while complete doesn't do anything. 1065 download->Resume(); 1066 ASSERT_EQ(GetSafeBufferChunk() * 3, download->GetReceivedBytes()); 1067 ASSERT_EQ(DownloadItem::COMPLETE, download->GetState()); 1068 RunAllPendingInMessageLoop(); 1069 ASSERT_EQ(GetSafeBufferChunk() * 3, download->GetReceivedBytes()); 1070 ASSERT_EQ(DownloadItem::COMPLETE, download->GetState()); 1071 } 1072 1073 // Confirm restart fallback happens if a range request is bounced. 1074 IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeInterruptedDownloadNoRange) { 1075 CommandLine::ForCurrentProcess()->AppendSwitch( 1076 switches::kEnableDownloadResumption); 1077 ASSERT_TRUE(test_server()->Start()); 1078 1079 // Auto-restart if server doesn't handle ranges. 1080 GURL url = test_server()->GetURL( 1081 base::StringPrintf( 1082 // First download hits an RST, rest don't, no ranges. 1083 "rangereset?size=%d&rst_boundary=%d&" 1084 "token=NoRange&rst_limit=1&bounce_range", 1085 GetSafeBufferChunk() * 3, GetSafeBufferChunk())); 1086 1087 // Start the download and wait for first data chunk. 1088 DownloadItem* download(StartDownloadAndReturnItem(url)); 1089 WaitForData(download, GetSafeBufferChunk()); 1090 1091 RecordingDownloadObserver recorder(download); 1092 1093 ReleaseRSTAndConfirmInterruptForResume(download); 1094 ConfirmFileStatusForResume( 1095 download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3, 1096 base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload"))); 1097 1098 DownloadUpdatedObserver completion_observer( 1099 download, base::Bind(DownloadCompleteFilter)); 1100 download->Resume(); 1101 completion_observer.WaitForEvent(); 1102 1103 ConfirmFileStatusForResume( 1104 download, true, GetSafeBufferChunk() * 3, GetSafeBufferChunk() * 3, 1105 base::FilePath(FILE_PATH_LITERAL("rangereset"))); 1106 1107 static const RecordingDownloadObserver::RecordStruct expected_record[] = { 1108 // Result of RST 1109 {DownloadItem::INTERRUPTED, GetSafeBufferChunk()}, 1110 // Starting continuation 1111 {DownloadItem::IN_PROGRESS, GetSafeBufferChunk()}, 1112 // Notification of receiving whole file. 1113 {DownloadItem::IN_PROGRESS, 0}, 1114 // Completion. 1115 {DownloadItem::COMPLETE, GetSafeBufferChunk() * 3}, 1116 }; 1117 1118 recorder.CompareToExpectedRecord(expected_record, arraysize(expected_record)); 1119 } 1120 1121 // Confirm restart fallback happens if a precondition is failed. 1122 IN_PROC_BROWSER_TEST_F(DownloadContentTest, 1123 ResumeInterruptedDownloadBadPrecondition) { 1124 CommandLine::ForCurrentProcess()->AppendSwitch( 1125 switches::kEnableDownloadResumption); 1126 ASSERT_TRUE(test_server()->Start()); 1127 1128 GURL url = test_server()->GetURL(base::StringPrintf( 1129 // First download hits an RST, rest don't, precondition fail. 1130 "rangereset?size=%d&rst_boundary=%d&" 1131 "token=BadPrecondition&rst_limit=1&fail_precondition=2", 1132 GetSafeBufferChunk() * 3, 1133 GetSafeBufferChunk())); 1134 1135 // Start the download and wait for first data chunk. 1136 DownloadItem* download(StartDownloadAndReturnItem(url)); 1137 WaitForData(download, GetSafeBufferChunk()); 1138 1139 RecordingDownloadObserver recorder(download); 1140 1141 ReleaseRSTAndConfirmInterruptForResume(download); 1142 ConfirmFileStatusForResume( 1143 download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3, 1144 base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload"))); 1145 EXPECT_EQ("BadPrecondition2", download->GetETag()); 1146 1147 DownloadUpdatedObserver completion_observer( 1148 download, base::Bind(DownloadCompleteFilter)); 1149 download->Resume(); 1150 completion_observer.WaitForEvent(); 1151 1152 ConfirmFileStatusForResume( 1153 download, true, GetSafeBufferChunk() * 3, GetSafeBufferChunk() * 3, 1154 base::FilePath(FILE_PATH_LITERAL("rangereset"))); 1155 EXPECT_EQ("BadPrecondition0", download->GetETag()); 1156 1157 static const RecordingDownloadObserver::RecordStruct expected_record[] = { 1158 // Result of RST 1159 {DownloadItem::INTERRUPTED, GetSafeBufferChunk()}, 1160 // Starting continuation 1161 {DownloadItem::IN_PROGRESS, GetSafeBufferChunk()}, 1162 // Server precondition fail. 1163 {DownloadItem::INTERRUPTED, 0}, 1164 // Notification of successful restart. 1165 {DownloadItem::IN_PROGRESS, 0}, 1166 // Completion. 1167 {DownloadItem::COMPLETE, GetSafeBufferChunk() * 3}, 1168 }; 1169 1170 recorder.CompareToExpectedRecord(expected_record, arraysize(expected_record)); 1171 } 1172 1173 // Confirm we don't try to resume if we don't have a verifier. 1174 IN_PROC_BROWSER_TEST_F(DownloadContentTest, 1175 ResumeInterruptedDownloadNoVerifiers) { 1176 CommandLine::ForCurrentProcess()->AppendSwitch( 1177 switches::kEnableDownloadResumption); 1178 ASSERT_TRUE(test_server()->Start()); 1179 1180 GURL url = test_server()->GetURL( 1181 base::StringPrintf( 1182 // First download hits an RST, rest don't, no verifiers. 1183 "rangereset?size=%d&rst_boundary=%d&" 1184 "token=NoRange&rst_limit=1&no_verifiers", 1185 GetSafeBufferChunk() * 3, GetSafeBufferChunk())); 1186 1187 // Start the download and wait for first data chunk. 1188 DownloadItem* download(StartDownloadAndReturnItem(url)); 1189 WaitForData(download, GetSafeBufferChunk()); 1190 1191 RecordingDownloadObserver recorder(download); 1192 1193 ReleaseRSTAndConfirmInterruptForResume(download); 1194 ConfirmFileStatusForResume( 1195 download, false, GetSafeBufferChunk(), GetSafeBufferChunk() * 3, 1196 base::FilePath()); 1197 1198 DownloadUpdatedObserver completion_observer( 1199 download, base::Bind(DownloadCompleteFilter)); 1200 download->Resume(); 1201 completion_observer.WaitForEvent(); 1202 1203 ConfirmFileStatusForResume( 1204 download, true, GetSafeBufferChunk() * 3, GetSafeBufferChunk() * 3, 1205 base::FilePath(FILE_PATH_LITERAL("rangereset"))); 1206 1207 static const RecordingDownloadObserver::RecordStruct expected_record[] = { 1208 // Result of RST 1209 {DownloadItem::INTERRUPTED, GetSafeBufferChunk()}, 1210 // Restart for lack of verifiers 1211 {DownloadItem::IN_PROGRESS, 0}, 1212 // Completion. 1213 {DownloadItem::COMPLETE, GetSafeBufferChunk() * 3}, 1214 }; 1215 1216 recorder.CompareToExpectedRecord(expected_record, arraysize(expected_record)); 1217 } 1218 1219 IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeWithDeletedFile) { 1220 CommandLine::ForCurrentProcess()->AppendSwitch( 1221 switches::kEnableDownloadResumption); 1222 ASSERT_TRUE(test_server()->Start()); 1223 1224 GURL url = test_server()->GetURL( 1225 base::StringPrintf( 1226 // First download hits an RST, rest don't 1227 "rangereset?size=%d&rst_boundary=%d&" 1228 "token=NoRange&rst_limit=1", 1229 GetSafeBufferChunk() * 3, GetSafeBufferChunk())); 1230 1231 // Start the download and wait for first data chunk. 1232 DownloadItem* download(StartDownloadAndReturnItem(url)); 1233 WaitForData(download, GetSafeBufferChunk()); 1234 1235 RecordingDownloadObserver recorder(download); 1236 1237 ReleaseRSTAndConfirmInterruptForResume(download); 1238 ConfirmFileStatusForResume( 1239 download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3, 1240 base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload"))); 1241 1242 // Delete the intermediate file. 1243 base::DeleteFile(download->GetFullPath(), false); 1244 1245 DownloadUpdatedObserver completion_observer( 1246 download, base::Bind(DownloadCompleteFilter)); 1247 download->Resume(); 1248 completion_observer.WaitForEvent(); 1249 1250 ConfirmFileStatusForResume( 1251 download, true, GetSafeBufferChunk() * 3, GetSafeBufferChunk() * 3, 1252 base::FilePath(FILE_PATH_LITERAL("rangereset"))); 1253 1254 static const RecordingDownloadObserver::RecordStruct expected_record[] = { 1255 // Result of RST 1256 {DownloadItem::INTERRUPTED, GetSafeBufferChunk()}, 1257 // Starting continuation 1258 {DownloadItem::IN_PROGRESS, GetSafeBufferChunk()}, 1259 // Error because file isn't there. 1260 {DownloadItem::INTERRUPTED, 0}, 1261 // Restart. 1262 {DownloadItem::IN_PROGRESS, 0}, 1263 // Completion. 1264 {DownloadItem::COMPLETE, GetSafeBufferChunk() * 3}, 1265 }; 1266 1267 recorder.CompareToExpectedRecord(expected_record, arraysize(expected_record)); 1268 } 1269 1270 IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeWithFileInitError) { 1271 CommandLine::ForCurrentProcess()->AppendSwitch( 1272 switches::kEnableDownloadResumption); 1273 base::FilePath file(FILE_PATH_LITERAL("download-test.lib")); 1274 GURL url(URLRequestMockHTTPJob::GetMockUrl(file)); 1275 1276 // Setup the error injector. 1277 scoped_refptr<TestFileErrorInjector> injector( 1278 TestFileErrorInjector::Create(DownloadManagerForShell(shell()))); 1279 1280 TestFileErrorInjector::FileErrorInfo err = { 1281 url.spec(), 1282 TestFileErrorInjector::FILE_OPERATION_INITIALIZE, 1283 0, 1284 DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE 1285 }; 1286 injector->AddError(err); 1287 injector->InjectErrors(); 1288 1289 // Start and watch for interrupt. 1290 scoped_ptr<DownloadTestObserver> int_observer( 1291 CreateInterruptedWaiter(shell(), 1)); 1292 DownloadItem* download(StartDownloadAndReturnItem(url)); 1293 int_observer->WaitForFinished(); 1294 ASSERT_EQ(DownloadItem::INTERRUPTED, download->GetState()); 1295 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE, 1296 download->GetLastReason()); 1297 EXPECT_EQ(0, download->GetReceivedBytes()); 1298 EXPECT_TRUE(download->GetFullPath().empty()); 1299 EXPECT_TRUE(download->GetTargetFilePath().empty()); 1300 1301 // We need to make sure that any cross-thread downloads communication has 1302 // quiesced before clearing and injecting the new errors, as the 1303 // InjectErrors() routine alters the currently in use download file 1304 // factory, which is a file thread object. 1305 RunAllPendingInMessageLoop(BrowserThread::FILE); 1306 RunAllPendingInMessageLoop(); 1307 1308 // Clear the old errors list. 1309 injector->ClearErrors(); 1310 injector->InjectErrors(); 1311 1312 // Resume and watch completion. 1313 DownloadUpdatedObserver completion_observer( 1314 download, base::Bind(DownloadCompleteFilter)); 1315 download->Resume(); 1316 completion_observer.WaitForEvent(); 1317 EXPECT_EQ(download->GetState(), DownloadItem::COMPLETE); 1318 } 1319 1320 IN_PROC_BROWSER_TEST_F(DownloadContentTest, 1321 ResumeWithFileIntermediateRenameError) { 1322 CommandLine::ForCurrentProcess()->AppendSwitch( 1323 switches::kEnableDownloadResumption); 1324 base::FilePath file(FILE_PATH_LITERAL("download-test.lib")); 1325 GURL url(URLRequestMockHTTPJob::GetMockUrl(file)); 1326 1327 // Setup the error injector. 1328 scoped_refptr<TestFileErrorInjector> injector( 1329 TestFileErrorInjector::Create(DownloadManagerForShell(shell()))); 1330 1331 TestFileErrorInjector::FileErrorInfo err = { 1332 url.spec(), 1333 TestFileErrorInjector::FILE_OPERATION_RENAME_UNIQUIFY, 1334 0, 1335 DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE 1336 }; 1337 injector->AddError(err); 1338 injector->InjectErrors(); 1339 1340 // Start and watch for interrupt. 1341 scoped_ptr<DownloadTestObserver> int_observer( 1342 CreateInterruptedWaiter(shell(), 1)); 1343 DownloadItem* download(StartDownloadAndReturnItem(url)); 1344 int_observer->WaitForFinished(); 1345 ASSERT_EQ(DownloadItem::INTERRUPTED, download->GetState()); 1346 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE, 1347 download->GetLastReason()); 1348 EXPECT_TRUE(download->GetFullPath().empty()); 1349 // Target path will have been set after file name determination. GetFullPath() 1350 // being empty is sufficient to signal that filename determination needs to be 1351 // redone. 1352 EXPECT_FALSE(download->GetTargetFilePath().empty()); 1353 1354 // We need to make sure that any cross-thread downloads communication has 1355 // quiesced before clearing and injecting the new errors, as the 1356 // InjectErrors() routine alters the currently in use download file 1357 // factory, which is a file thread object. 1358 RunAllPendingInMessageLoop(BrowserThread::FILE); 1359 RunAllPendingInMessageLoop(); 1360 1361 // Clear the old errors list. 1362 injector->ClearErrors(); 1363 injector->InjectErrors(); 1364 1365 // Resume and watch completion. 1366 DownloadUpdatedObserver completion_observer( 1367 download, base::Bind(DownloadCompleteFilter)); 1368 download->Resume(); 1369 completion_observer.WaitForEvent(); 1370 EXPECT_EQ(download->GetState(), DownloadItem::COMPLETE); 1371 } 1372 1373 IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeWithFileFinalRenameError) { 1374 CommandLine::ForCurrentProcess()->AppendSwitch( 1375 switches::kEnableDownloadResumption); 1376 base::FilePath file(FILE_PATH_LITERAL("download-test.lib")); 1377 GURL url(URLRequestMockHTTPJob::GetMockUrl(file)); 1378 1379 // Setup the error injector. 1380 scoped_refptr<TestFileErrorInjector> injector( 1381 TestFileErrorInjector::Create(DownloadManagerForShell(shell()))); 1382 1383 DownloadManagerForShell(shell())->RemoveAllDownloads(); 1384 TestFileErrorInjector::FileErrorInfo err = { 1385 url.spec(), 1386 TestFileErrorInjector::FILE_OPERATION_RENAME_ANNOTATE, 1387 0, 1388 DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE 1389 }; 1390 injector->AddError(err); 1391 injector->InjectErrors(); 1392 1393 // Start and watch for interrupt. 1394 scoped_ptr<DownloadTestObserver> int_observer( 1395 CreateInterruptedWaiter(shell(), 1)); 1396 DownloadItem* download(StartDownloadAndReturnItem(url)); 1397 int_observer->WaitForFinished(); 1398 ASSERT_EQ(DownloadItem::INTERRUPTED, download->GetState()); 1399 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE, 1400 download->GetLastReason()); 1401 EXPECT_TRUE(download->GetFullPath().empty()); 1402 // Target path should still be intact. 1403 EXPECT_FALSE(download->GetTargetFilePath().empty()); 1404 1405 // We need to make sure that any cross-thread downloads communication has 1406 // quiesced before clearing and injecting the new errors, as the 1407 // InjectErrors() routine alters the currently in use download file 1408 // factory, which is a file thread object. 1409 RunAllPendingInMessageLoop(BrowserThread::FILE); 1410 RunAllPendingInMessageLoop(); 1411 1412 // Clear the old errors list. 1413 injector->ClearErrors(); 1414 injector->InjectErrors(); 1415 1416 // Resume and watch completion. 1417 DownloadUpdatedObserver completion_observer( 1418 download, base::Bind(DownloadCompleteFilter)); 1419 download->Resume(); 1420 completion_observer.WaitForEvent(); 1421 EXPECT_EQ(download->GetState(), DownloadItem::COMPLETE); 1422 } 1423 1424 // An interrupted download should remove the intermediate file when it is 1425 // cancelled. 1426 IN_PROC_BROWSER_TEST_F(DownloadContentTest, CancelInterruptedDownload) { 1427 CommandLine::ForCurrentProcess()->AppendSwitch( 1428 switches::kEnableDownloadResumption); 1429 ASSERT_TRUE(test_server()->Start()); 1430 1431 GURL url1 = test_server()->GetURL( 1432 base::StringPrintf("rangereset?size=%d&rst_boundary=%d", 1433 GetSafeBufferChunk() * 3, GetSafeBufferChunk())); 1434 1435 DownloadItem* download(StartDownloadAndReturnItem(url1)); 1436 WaitForData(download, GetSafeBufferChunk()); 1437 1438 ReleaseRSTAndConfirmInterruptForResume(download); 1439 ConfirmFileStatusForResume( 1440 download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3, 1441 base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload"))); 1442 1443 base::FilePath intermediate_path(download->GetFullPath()); 1444 ASSERT_FALSE(intermediate_path.empty()); 1445 EXPECT_TRUE(base::PathExists(intermediate_path)); 1446 1447 download->Cancel(true /* user_cancel */); 1448 RunAllPendingInMessageLoop(BrowserThread::FILE); 1449 RunAllPendingInMessageLoop(); 1450 1451 // The intermediate file should now be gone. 1452 EXPECT_FALSE(base::PathExists(intermediate_path)); 1453 EXPECT_TRUE(download->GetFullPath().empty()); 1454 } 1455 1456 IN_PROC_BROWSER_TEST_F(DownloadContentTest, RemoveDownload) { 1457 CommandLine::ForCurrentProcess()->AppendSwitch( 1458 switches::kEnableDownloadResumption); 1459 ASSERT_TRUE(test_server()->Start()); 1460 1461 // An interrupted download should remove the intermediate file when it is 1462 // removed. 1463 { 1464 GURL url1 = test_server()->GetURL( 1465 base::StringPrintf("rangereset?size=%d&rst_boundary=%d", 1466 GetSafeBufferChunk() * 3, GetSafeBufferChunk())); 1467 1468 DownloadItem* download(StartDownloadAndReturnItem(url1)); 1469 WaitForData(download, GetSafeBufferChunk()); 1470 ReleaseRSTAndConfirmInterruptForResume(download); 1471 ConfirmFileStatusForResume( 1472 download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3, 1473 base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload"))); 1474 1475 base::FilePath intermediate_path(download->GetFullPath()); 1476 ASSERT_FALSE(intermediate_path.empty()); 1477 EXPECT_TRUE(base::PathExists(intermediate_path)); 1478 1479 download->Remove(); 1480 RunAllPendingInMessageLoop(BrowserThread::FILE); 1481 RunAllPendingInMessageLoop(); 1482 1483 // The intermediate file should now be gone. 1484 EXPECT_FALSE(base::PathExists(intermediate_path)); 1485 } 1486 1487 // A completed download shouldn't delete the downloaded file when it is 1488 // removed. 1489 { 1490 // Start the second download and wait until it's done. 1491 base::FilePath file2(FILE_PATH_LITERAL("download-test.lib")); 1492 GURL url2(URLRequestMockHTTPJob::GetMockUrl(file2)); 1493 scoped_ptr<DownloadTestObserver> completion_observer( 1494 CreateWaiter(shell(), 1)); 1495 DownloadItem* download(StartDownloadAndReturnItem(url2)); 1496 completion_observer->WaitForFinished(); 1497 1498 // The target path should exist. 1499 base::FilePath target_path(download->GetTargetFilePath()); 1500 EXPECT_TRUE(base::PathExists(target_path)); 1501 download->Remove(); 1502 RunAllPendingInMessageLoop(BrowserThread::FILE); 1503 RunAllPendingInMessageLoop(); 1504 1505 // The file should still exist. 1506 EXPECT_TRUE(base::PathExists(target_path)); 1507 } 1508 } 1509 1510 IN_PROC_BROWSER_TEST_F(DownloadContentTest, RemoveResumingDownload) { 1511 SetupEnsureNoPendingDownloads(); 1512 CommandLine::ForCurrentProcess()->AppendSwitch( 1513 switches::kEnableDownloadResumption); 1514 ASSERT_TRUE(test_server()->Start()); 1515 1516 GURL url = test_server()->GetURL( 1517 base::StringPrintf("rangereset?size=%d&rst_boundary=%d", 1518 GetSafeBufferChunk() * 3, GetSafeBufferChunk())); 1519 1520 MockDownloadManagerObserver dm_observer(DownloadManagerForShell(shell())); 1521 EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(1); 1522 1523 DownloadItem* download(StartDownloadAndReturnItem(url)); 1524 WaitForData(download, GetSafeBufferChunk()); 1525 ::testing::Mock::VerifyAndClearExpectations(&dm_observer); 1526 1527 // Tell the server to send the RST and confirm the interrupt happens. 1528 ReleaseRSTAndConfirmInterruptForResume(download); 1529 ConfirmFileStatusForResume( 1530 download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3, 1531 base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload"))); 1532 1533 base::FilePath intermediate_path(download->GetFullPath()); 1534 ASSERT_FALSE(intermediate_path.empty()); 1535 EXPECT_TRUE(base::PathExists(intermediate_path)); 1536 1537 // Resume and remove download. We expect only a single OnDownloadCreated() 1538 // call, and that's for the second download created below. 1539 EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(1); 1540 download->Resume(); 1541 download->Remove(); 1542 1543 // The intermediate file should now be gone. 1544 RunAllPendingInMessageLoop(BrowserThread::FILE); 1545 RunAllPendingInMessageLoop(); 1546 EXPECT_FALSE(base::PathExists(intermediate_path)); 1547 1548 // Start the second download and wait until it's done. The test server is 1549 // single threaded. The response to this download request should follow the 1550 // response to the previous resumption request. 1551 GURL url2(test_server()->GetURL("rangereset?size=100&rst_limit=0&token=x")); 1552 DownloadAndWait(shell(), url2, DownloadItem::COMPLETE); 1553 1554 EXPECT_TRUE(EnsureNoPendingDownloads()); 1555 } 1556 1557 IN_PROC_BROWSER_TEST_F(DownloadContentTest, CancelResumingDownload) { 1558 SetupEnsureNoPendingDownloads(); 1559 CommandLine::ForCurrentProcess()->AppendSwitch( 1560 switches::kEnableDownloadResumption); 1561 ASSERT_TRUE(test_server()->Start()); 1562 1563 GURL url = test_server()->GetURL( 1564 base::StringPrintf("rangereset?size=%d&rst_boundary=%d", 1565 GetSafeBufferChunk() * 3, GetSafeBufferChunk())); 1566 1567 MockDownloadManagerObserver dm_observer(DownloadManagerForShell(shell())); 1568 EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(1); 1569 1570 DownloadItem* download(StartDownloadAndReturnItem(url)); 1571 WaitForData(download, GetSafeBufferChunk()); 1572 ::testing::Mock::VerifyAndClearExpectations(&dm_observer); 1573 1574 // Tell the server to send the RST and confirm the interrupt happens. 1575 ReleaseRSTAndConfirmInterruptForResume(download); 1576 ConfirmFileStatusForResume( 1577 download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3, 1578 base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload"))); 1579 1580 base::FilePath intermediate_path(download->GetFullPath()); 1581 ASSERT_FALSE(intermediate_path.empty()); 1582 EXPECT_TRUE(base::PathExists(intermediate_path)); 1583 1584 // Resume and cancel download. We expect only a single OnDownloadCreated() 1585 // call, and that's for the second download created below. 1586 EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(1); 1587 download->Resume(); 1588 download->Cancel(true); 1589 1590 // The intermediate file should now be gone. 1591 RunAllPendingInMessageLoop(BrowserThread::FILE); 1592 RunAllPendingInMessageLoop(); 1593 EXPECT_FALSE(base::PathExists(intermediate_path)); 1594 EXPECT_TRUE(download->GetFullPath().empty()); 1595 1596 // Start the second download and wait until it's done. The test server is 1597 // single threaded. The response to this download request should follow the 1598 // response to the previous resumption request. 1599 GURL url2(test_server()->GetURL("rangereset?size=100&rst_limit=0&token=x")); 1600 DownloadAndWait(shell(), url2, DownloadItem::COMPLETE); 1601 1602 EXPECT_TRUE(EnsureNoPendingDownloads()); 1603 } 1604 1605 // Check that the cookie policy is correctly updated when downloading a file 1606 // that redirects cross origin. 1607 IN_PROC_BROWSER_TEST_F(DownloadContentTest, CookiePolicy) { 1608 ASSERT_TRUE(test_server()->Start()); 1609 net::HostPortPair host_port = test_server()->host_port_pair(); 1610 DCHECK_EQ(host_port.host(), std::string("127.0.0.1")); 1611 1612 // Block third-party cookies. 1613 ShellNetworkDelegate::SetAcceptAllCookies(false); 1614 1615 // |url| redirects to a different origin |download| which tries to set a 1616 // cookie. 1617 std::string download(base::StringPrintf( 1618 "http://localhost:%d/set-cookie?A=B", host_port.port())); 1619 GURL url(test_server()->GetURL("server-redirect?" + download)); 1620 1621 // Download the file. 1622 SetupEnsureNoPendingDownloads(); 1623 scoped_ptr<DownloadUrlParameters> dl_params( 1624 DownloadUrlParameters::FromWebContents(shell()->web_contents(), url)); 1625 scoped_ptr<DownloadTestObserver> observer(CreateWaiter(shell(), 1)); 1626 DownloadManagerForShell(shell())->DownloadUrl(dl_params.Pass()); 1627 observer->WaitForFinished(); 1628 1629 // Get the important info from other threads and check it. 1630 EXPECT_TRUE(EnsureNoPendingDownloads()); 1631 1632 std::vector<DownloadItem*> downloads; 1633 DownloadManagerForShell(shell())->GetAllDownloads(&downloads); 1634 ASSERT_EQ(1u, downloads.size()); 1635 ASSERT_EQ(DownloadItem::COMPLETE, downloads[0]->GetState()); 1636 1637 // Check that the cookies were correctly set. 1638 EXPECT_EQ("A=B", 1639 content::GetCookies(shell()->web_contents()->GetBrowserContext(), 1640 GURL(download))); 1641 } 1642 1643 } // namespace content 1644