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 #include "base/files/file_path.h" 6 #include "base/files/scoped_temp_dir.h" 7 #include "base/message_loop/message_loop.h" 8 #include "base/observer_list.h" 9 #include "base/prefs/pref_service.h" 10 #include "base/run_loop.h" 11 #include "base/stl_util.h" 12 #include "base/strings/string_util.h" 13 #include "base/value_conversions.h" 14 #include "chrome/browser/download/chrome_download_manager_delegate.h" 15 #include "chrome/browser/download/download_extensions.h" 16 #include "chrome/browser/download/download_prefs.h" 17 #include "chrome/browser/download/download_target_determiner.h" 18 #include "chrome/browser/download/download_util.h" 19 #include "chrome/browser/history/history_service.h" 20 #include "chrome/browser/history/history_service_factory.h" 21 #include "chrome/browser/history/history_types.h" 22 #include "chrome/common/extensions/extension.h" 23 #include "chrome/common/pref_names.h" 24 #include "chrome/test/base/chrome_render_view_host_test_harness.h" 25 #include "chrome/test/base/testing_pref_service_syncable.h" 26 #include "chrome/test/base/testing_profile.h" 27 #include "content/public/browser/download_interrupt_reasons.h" 28 #include "content/public/browser/web_contents.h" 29 #include "content/public/browser/web_contents_delegate.h" 30 #include "content/public/test/mock_download_item.h" 31 #include "content/public/test/test_browser_thread.h" 32 #include "content/public/test/test_renderer_host.h" 33 #include "content/public/test/web_contents_tester.h" 34 #include "testing/gmock/include/gmock/gmock.h" 35 #include "testing/gtest/include/gtest/gtest.h" 36 37 using ::testing::AnyNumber; 38 using ::testing::Invoke; 39 using ::testing::Ref; 40 using ::testing::Return; 41 using ::testing::ReturnRef; 42 using ::testing::ReturnRefOfCopy; 43 using ::testing::Truly; 44 using ::testing::WithArg; 45 using ::testing::_; 46 using content::DownloadItem; 47 48 namespace { 49 50 // No-op delegate. 51 class NullWebContentsDelegate : public content::WebContentsDelegate { 52 public: 53 NullWebContentsDelegate() {} 54 virtual ~NullWebContentsDelegate() {} 55 }; 56 57 // Google Mock action that posts a task to the current message loop that invokes 58 // the first argument of the mocked method as a callback. Said argument must be 59 // a base::Callback<void(ParamType)>. |result| must be of |ParamType| and is 60 // bound as that parameter. 61 // Example: 62 // class FooClass { 63 // public: 64 // virtual void Foo(base::Callback<void(bool)> callback); 65 // }; 66 // ... 67 // EXPECT_CALL(mock_fooclass_instance, Foo(callback)) 68 // .WillOnce(ScheduleCallback(false)); 69 ACTION_P(ScheduleCallback, result0) { 70 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(arg0, result0)); 71 } 72 73 // Similar to ScheduleCallback, but binds 2 arguments. 74 ACTION_P2(ScheduleCallback2, result0, result1) { 75 base::MessageLoop::current()->PostTask( 76 FROM_HERE, base::Bind(arg0, result0, result1)); 77 } 78 79 // Used with DownloadTestCase. Indicates the type of test case. The expectations 80 // for the test is set based on the type. 81 enum TestCaseType { 82 SAVE_AS, 83 AUTOMATIC, 84 FORCED // Requires that forced_file_path be non-empty. 85 }; 86 87 // Used with DownloadTestCase. Type of intermediate filename to expect. 88 enum TestCaseExpectIntermediate { 89 EXPECT_CRDOWNLOAD, // Expect path/to/target.crdownload. 90 EXPECT_UNCONFIRMED, // Expect path/to/Unconfirmed xxx.crdownload. 91 EXPECT_LOCAL_PATH, // Expect target path. 92 }; 93 94 // Typical download test case. Used with 95 // DownloadTargetDeterminerTest::RunTestCase(). 96 struct DownloadTestCase { 97 // Type of test. 98 TestCaseType test_type; 99 100 // Expected danger type. Verified at the end of target determination. 101 content::DownloadDangerType expected_danger_type; 102 103 // Value of DownloadItem::GetURL() 104 const char* url; 105 106 // Value of DownloadItem::GetMimeType() 107 const char* mime_type; 108 109 // Should be non-empty if |test_type| == FORCED. Value of GetForcedFilePath(). 110 const base::FilePath::CharType* forced_file_path; 111 112 // Expected virtual path. Specified relative to the virtual download path. If 113 // empty, assumed to be the same as |expected_local_path|. 114 const base::FilePath::CharType* expected_virtual_path; 115 116 // Expected local path. Specified relative to the test download path. 117 const base::FilePath::CharType* expected_local_path; 118 119 // Expected target disposition. If this is TARGET_DISPOSITION_PROMPT, then the 120 // test run will expect ChromeDownloadManagerDelegate to prompt the user for a 121 // download location. 122 DownloadItem::TargetDisposition expected_disposition; 123 124 // Type of intermediate path to expect. 125 TestCaseExpectIntermediate expected_intermediate; 126 }; 127 128 class MockDownloadTargetDeterminerDelegate 129 : public DownloadTargetDeterminerDelegate { 130 public: 131 MOCK_METHOD3(CheckDownloadUrl, 132 void(content::DownloadItem*, const base::FilePath&, 133 const CheckDownloadUrlCallback&)); 134 MOCK_METHOD3(NotifyExtensions, 135 void(content::DownloadItem*, const base::FilePath&, 136 const NotifyExtensionsCallback&)); 137 MOCK_METHOD3(PromptUserForDownloadPath, 138 void(content::DownloadItem*, const base::FilePath&, 139 const FileSelectedCallback&)); 140 MOCK_METHOD3(DetermineLocalPath, 141 void(DownloadItem*, const base::FilePath&, 142 const LocalPathCallback&)); 143 MOCK_METHOD5(ReserveVirtualPath, 144 void(DownloadItem*, const base::FilePath&, bool, 145 DownloadPathReservationTracker::FilenameConflictAction, 146 const ReservedPathCallback&)); 147 148 void SetupDefaults() { 149 ON_CALL(*this, CheckDownloadUrl(_, _, _)) 150 .WillByDefault(WithArg<2>( 151 ScheduleCallback(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS))); 152 ON_CALL(*this, NotifyExtensions(_, _, _)) 153 .WillByDefault(WithArg<2>( 154 ScheduleCallback2(base::FilePath(), 155 DownloadPathReservationTracker::UNIQUIFY))); 156 ON_CALL(*this, ReserveVirtualPath(_, _, _, _, _)) 157 .WillByDefault(Invoke( 158 &MockDownloadTargetDeterminerDelegate::NullReserveVirtualPath)); 159 ON_CALL(*this, PromptUserForDownloadPath(_, _, _)) 160 .WillByDefault(Invoke( 161 &MockDownloadTargetDeterminerDelegate::NullPromptUser)); 162 ON_CALL(*this, DetermineLocalPath(_, _, _)) 163 .WillByDefault(Invoke( 164 &MockDownloadTargetDeterminerDelegate::NullDetermineLocalPath)); 165 } 166 private: 167 static void NullReserveVirtualPath( 168 DownloadItem* download, 169 const base::FilePath& virtual_path, 170 bool create_directory, 171 DownloadPathReservationTracker::FilenameConflictAction conflict_action, 172 const DownloadTargetDeterminerDelegate::ReservedPathCallback& callback); 173 static void NullPromptUser( 174 DownloadItem* download, const base::FilePath& suggested_path, 175 const FileSelectedCallback& callback); 176 static void NullDetermineLocalPath( 177 DownloadItem* download, const base::FilePath& virtual_path, 178 const LocalPathCallback& callback); 179 }; 180 181 class DownloadTargetDeterminerTest : public ChromeRenderViewHostTestHarness { 182 public: 183 // ::testing::Test 184 virtual void SetUp() OVERRIDE; 185 virtual void TearDown() OVERRIDE; 186 187 // Creates MockDownloadItem and sets up default expectations. 188 content::MockDownloadItem* CreateActiveDownloadItem( 189 int32 id, 190 const DownloadTestCase& test_case); 191 192 // Sets the AutoOpenBasedOnExtension user preference for |path|. 193 void EnableAutoOpenBasedOnExtension(const base::FilePath& path); 194 195 // Set the kDownloadDefaultDirectory managed preference to |path|. 196 void SetManagedDownloadPath(const base::FilePath& path); 197 198 // Set the kPromptForDownload user preference to |prompt|. 199 void SetPromptForDownload(bool prompt); 200 201 // Given the relative path |path|, returns the full path under the temporary 202 // downloads directory. 203 base::FilePath GetPathInDownloadDir(const base::FilePath::StringType& path); 204 205 // Run |test_case| using |item|. 206 void RunTestCase(const DownloadTestCase& test_case, 207 const base::FilePath& initial_virtual_path, 208 content::MockDownloadItem* item); 209 210 // Run through |test_case_count| tests in |test_cases|. A new MockDownloadItem 211 // will be created for each test case and destroyed when the test case is 212 // complete. 213 void RunTestCasesWithActiveItem(const DownloadTestCase test_cases[], 214 size_t test_case_count); 215 216 // Verifies that |target_path|, |disposition|, |expected_danger_type| and 217 // |intermediate_path| matches the expectations of |test_case|. Posts 218 // |closure| to the current message loop when done. 219 void DownloadTargetVerifier(const base::Closure& closure, 220 const DownloadTestCase& test_case, 221 const base::FilePath& local_path, 222 DownloadItem::TargetDisposition disposition, 223 content::DownloadDangerType danger_type, 224 const base::FilePath& intermediate_path); 225 226 const base::FilePath& test_download_dir() const { 227 return test_download_dir_.path(); 228 } 229 230 const base::FilePath& test_virtual_dir() const { 231 return test_virtual_dir_; 232 } 233 234 MockDownloadTargetDeterminerDelegate* delegate() { 235 return &delegate_; 236 } 237 238 DownloadPrefs* download_prefs() { 239 return download_prefs_.get(); 240 } 241 242 private: 243 scoped_ptr<DownloadPrefs> download_prefs_; 244 ::testing::NiceMock<MockDownloadTargetDeterminerDelegate> delegate_; 245 NullWebContentsDelegate web_contents_delegate_; 246 base::ScopedTempDir test_download_dir_; 247 base::FilePath test_virtual_dir_; 248 }; 249 250 void DownloadTargetDeterminerTest::SetUp() { 251 ChromeRenderViewHostTestHarness::SetUp(); 252 CHECK(profile()); 253 download_prefs_.reset(new DownloadPrefs(profile())); 254 web_contents()->SetDelegate(&web_contents_delegate_); 255 ASSERT_TRUE(test_download_dir_.CreateUniqueTempDir()); 256 test_virtual_dir_ = test_download_dir().Append(FILE_PATH_LITERAL("virtual")); 257 download_prefs_->SetDownloadPath(test_download_dir()); 258 delegate_.SetupDefaults(); 259 } 260 261 void DownloadTargetDeterminerTest::TearDown() { 262 download_prefs_.reset(); 263 ChromeRenderViewHostTestHarness::TearDown(); 264 } 265 266 content::MockDownloadItem* 267 DownloadTargetDeterminerTest::CreateActiveDownloadItem( 268 int32 id, 269 const DownloadTestCase& test_case) { 270 content::MockDownloadItem* item = 271 new ::testing::NiceMock<content::MockDownloadItem>(); 272 GURL download_url(test_case.url); 273 std::vector<GURL> url_chain; 274 url_chain.push_back(download_url); 275 base::FilePath forced_file_path = 276 GetPathInDownloadDir(test_case.forced_file_path); 277 DownloadItem::TargetDisposition initial_disposition = 278 (test_case.test_type == SAVE_AS) ? 279 DownloadItem::TARGET_DISPOSITION_PROMPT : 280 DownloadItem::TARGET_DISPOSITION_OVERWRITE; 281 EXPECT_EQ(test_case.test_type == FORCED, 282 !forced_file_path.empty()); 283 284 ON_CALL(*item, GetBrowserContext()) 285 .WillByDefault(Return(profile())); 286 ON_CALL(*item, GetDangerType()) 287 .WillByDefault(Return(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS)); 288 ON_CALL(*item, GetForcedFilePath()) 289 .WillByDefault(ReturnRefOfCopy(forced_file_path)); 290 ON_CALL(*item, GetFullPath()) 291 .WillByDefault(ReturnRefOfCopy(base::FilePath())); 292 ON_CALL(*item, GetHash()) 293 .WillByDefault(ReturnRefOfCopy(std::string())); 294 ON_CALL(*item, GetId()) 295 .WillByDefault(Return(id)); 296 ON_CALL(*item, GetLastReason()) 297 .WillByDefault(Return(content::DOWNLOAD_INTERRUPT_REASON_NONE)); 298 ON_CALL(*item, GetMimeType()) 299 .WillByDefault(Return(test_case.mime_type)); 300 ON_CALL(*item, GetReferrerUrl()) 301 .WillByDefault(ReturnRefOfCopy(download_url)); 302 ON_CALL(*item, GetState()) 303 .WillByDefault(Return(DownloadItem::IN_PROGRESS)); 304 ON_CALL(*item, GetTargetDisposition()) 305 .WillByDefault(Return(initial_disposition)); 306 ON_CALL(*item, GetTargetFilePath()) 307 .WillByDefault(ReturnRefOfCopy(base::FilePath())); 308 ON_CALL(*item, GetTransitionType()) 309 .WillByDefault(Return(content::PAGE_TRANSITION_LINK)); 310 ON_CALL(*item, GetURL()) 311 .WillByDefault(ReturnRefOfCopy(download_url)); 312 ON_CALL(*item, GetUrlChain()) 313 .WillByDefault(ReturnRefOfCopy(url_chain)); 314 ON_CALL(*item, GetWebContents()) 315 .WillByDefault(Return(web_contents())); 316 ON_CALL(*item, HasUserGesture()) 317 .WillByDefault(Return(true)); 318 ON_CALL(*item, IsDangerous()) 319 .WillByDefault(Return(false)); 320 ON_CALL(*item, IsTemporary()) 321 .WillByDefault(Return(false)); 322 return item; 323 } 324 325 void DownloadTargetDeterminerTest::EnableAutoOpenBasedOnExtension( 326 const base::FilePath& path) { 327 EXPECT_TRUE(download_prefs_->EnableAutoOpenBasedOnExtension(path)); 328 } 329 330 void DownloadTargetDeterminerTest::SetManagedDownloadPath( 331 const base::FilePath& path) { 332 profile()->GetTestingPrefService()-> 333 SetManagedPref(prefs::kDownloadDefaultDirectory, 334 base::CreateFilePathValue(path)); 335 } 336 337 void DownloadTargetDeterminerTest::SetPromptForDownload(bool prompt) { 338 profile()->GetTestingPrefService()-> 339 SetBoolean(prefs::kPromptForDownload, prompt); 340 } 341 342 base::FilePath DownloadTargetDeterminerTest::GetPathInDownloadDir( 343 const base::FilePath::StringType& relative_path) { 344 if (relative_path.empty()) 345 return base::FilePath(); 346 base::FilePath full_path(test_download_dir().Append(relative_path)); 347 return full_path.NormalizePathSeparators(); 348 } 349 350 void DownloadTargetDeterminerTest::RunTestCase( 351 const DownloadTestCase& test_case, 352 const base::FilePath& initial_virtual_path, 353 content::MockDownloadItem* item) { 354 // Kick off the test. 355 base::WeakPtrFactory<DownloadTargetDeterminerTest> factory(this); 356 base::RunLoop run_loop; 357 DownloadTargetDeterminer::Start( 358 item, initial_virtual_path, download_prefs_.get(), delegate(), 359 base::Bind(&DownloadTargetDeterminerTest::DownloadTargetVerifier, 360 factory.GetWeakPtr(), run_loop.QuitClosure(), test_case)); 361 run_loop.Run(); 362 ::testing::Mock::VerifyAndClearExpectations(delegate()); 363 } 364 365 void DownloadTargetDeterminerTest::RunTestCasesWithActiveItem( 366 const DownloadTestCase test_cases[], 367 size_t test_case_count) { 368 for (size_t i = 0; i < test_case_count; ++i) { 369 scoped_ptr<content::MockDownloadItem> item( 370 CreateActiveDownloadItem(i, test_cases[i])); 371 SCOPED_TRACE(testing::Message() << "Running test case " << i); 372 RunTestCase(test_cases[i], base::FilePath(), item.get()); 373 } 374 } 375 376 void DownloadTargetDeterminerTest::DownloadTargetVerifier( 377 const base::Closure& closure, 378 const DownloadTestCase& test_case, 379 const base::FilePath& local_path, 380 DownloadItem::TargetDisposition disposition, 381 content::DownloadDangerType danger_type, 382 const base::FilePath& intermediate_path) { 383 base::FilePath expected_local_path( 384 GetPathInDownloadDir(test_case.expected_local_path)); 385 EXPECT_EQ(expected_local_path.value(), local_path.value()); 386 EXPECT_EQ(test_case.expected_disposition, disposition); 387 EXPECT_EQ(test_case.expected_danger_type, danger_type); 388 389 switch (test_case.expected_intermediate) { 390 case EXPECT_CRDOWNLOAD: 391 EXPECT_EQ(DownloadTargetDeterminer::GetCrDownloadPath(local_path).value(), 392 intermediate_path.value()); 393 break; 394 395 case EXPECT_UNCONFIRMED: 396 // The paths (in English) look like: /path/Unconfirmed xxx.crdownload. 397 // Of this, we only check that the path is: 398 // 1. Not "/path/target.crdownload", 399 // 2. Points to the same directory as the target. 400 // 3. Has extension ".crdownload". 401 // 4. Basename starts with "Unconfirmed ". 402 EXPECT_NE(DownloadTargetDeterminer::GetCrDownloadPath(expected_local_path) 403 .value(), 404 intermediate_path.value()); 405 EXPECT_EQ(expected_local_path.DirName().value(), 406 intermediate_path.DirName().value()); 407 EXPECT_TRUE(intermediate_path.MatchesExtension( 408 FILE_PATH_LITERAL(".crdownload"))); 409 EXPECT_EQ(0u, intermediate_path.BaseName().value().find( 410 FILE_PATH_LITERAL("Unconfirmed "))); 411 break; 412 413 case EXPECT_LOCAL_PATH: 414 EXPECT_EQ(expected_local_path.value(), intermediate_path.value()); 415 break; 416 } 417 base::MessageLoop::current()->PostTask(FROM_HERE, closure); 418 } 419 420 // static 421 void MockDownloadTargetDeterminerDelegate::NullReserveVirtualPath( 422 DownloadItem* download, 423 const base::FilePath& virtual_path, 424 bool create_directory, 425 DownloadPathReservationTracker::FilenameConflictAction conflict_action, 426 const DownloadTargetDeterminerDelegate::ReservedPathCallback& callback) { 427 callback.Run(virtual_path, true); 428 } 429 430 // static 431 void MockDownloadTargetDeterminerDelegate::NullPromptUser( 432 DownloadItem* download, const base::FilePath& suggested_path, 433 const FileSelectedCallback& callback) { 434 callback.Run(suggested_path); 435 } 436 437 // static 438 void MockDownloadTargetDeterminerDelegate::NullDetermineLocalPath( 439 DownloadItem* download, const base::FilePath& virtual_path, 440 const LocalPathCallback& callback) { 441 callback.Run(virtual_path); 442 } 443 444 // NotifyExtensions implementation that overrides the path so that the target 445 // file is in a subdirectory called 'overridden'. If the extension is '.remove', 446 // the extension is removed. 447 void NotifyExtensionsOverridePath( 448 content::DownloadItem* download, 449 const base::FilePath& path, 450 const DownloadTargetDeterminerDelegate::NotifyExtensionsCallback& 451 callback) { 452 base::FilePath new_path = 453 base::FilePath() 454 .AppendASCII("overridden") 455 .Append(path.BaseName()); 456 if (new_path.MatchesExtension(FILE_PATH_LITERAL(".remove"))) 457 new_path = new_path.RemoveExtension(); 458 callback.Run(new_path, DownloadPathReservationTracker::UNIQUIFY); 459 } 460 461 void CheckDownloadUrlCheckExes( 462 content::DownloadItem* download, 463 const base::FilePath& path, 464 const DownloadTargetDeterminerDelegate::CheckDownloadUrlCallback& 465 callback) { 466 if (path.MatchesExtension(FILE_PATH_LITERAL(".exe"))) 467 callback.Run(content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT); 468 else 469 callback.Run(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS); 470 } 471 472 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_Basic) { 473 const DownloadTestCase kBasicTestCases[] = { 474 { 475 // 0: Automatic Safe 476 AUTOMATIC, 477 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 478 "http://example.com/foo.txt", "text/plain", 479 FILE_PATH_LITERAL(""), 480 481 FILE_PATH_LITERAL(""), 482 FILE_PATH_LITERAL("foo.txt"), 483 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 484 485 EXPECT_CRDOWNLOAD 486 }, 487 488 { 489 // 1: Save_As Safe 490 SAVE_AS, 491 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 492 "http://example.com/foo.txt", "text/plain", 493 FILE_PATH_LITERAL(""), 494 495 FILE_PATH_LITERAL(""), 496 FILE_PATH_LITERAL("foo.txt"), 497 DownloadItem::TARGET_DISPOSITION_PROMPT, 498 499 EXPECT_CRDOWNLOAD 500 }, 501 502 { 503 // 2: Automatic Dangerous 504 AUTOMATIC, 505 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE, 506 "http://example.com/foo.html", "", 507 FILE_PATH_LITERAL(""), 508 509 FILE_PATH_LITERAL(""), 510 FILE_PATH_LITERAL("foo.html"), 511 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 512 513 EXPECT_UNCONFIRMED 514 }, 515 516 { 517 // 3: Forced Safe 518 FORCED, 519 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 520 "http://example.com/foo.txt", "", 521 FILE_PATH_LITERAL("forced-foo.txt"), 522 523 FILE_PATH_LITERAL(""), 524 FILE_PATH_LITERAL("forced-foo.txt"), 525 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 526 527 EXPECT_LOCAL_PATH 528 }, 529 }; 530 531 // The test assumes that .html files have a danger level of 532 // ALLOW_ON_USER_GESTURE. 533 ASSERT_EQ(download_util::ALLOW_ON_USER_GESTURE, 534 download_util::GetFileDangerLevel( 535 base::FilePath(FILE_PATH_LITERAL("foo.html")))); 536 RunTestCasesWithActiveItem(kBasicTestCases, arraysize(kBasicTestCases)); 537 } 538 539 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_CancelSaveAs) { 540 const DownloadTestCase kCancelSaveAsTestCases[] = { 541 { 542 // 0: Save_As Safe, Cancelled. 543 SAVE_AS, 544 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 545 "http://example.com/foo.txt", "text/plain", 546 FILE_PATH_LITERAL(""), 547 548 FILE_PATH_LITERAL(""), 549 FILE_PATH_LITERAL(""), 550 DownloadItem::TARGET_DISPOSITION_PROMPT, 551 552 EXPECT_LOCAL_PATH 553 } 554 }; 555 ON_CALL(*delegate(), PromptUserForDownloadPath(_, _, _)) 556 .WillByDefault(WithArg<2>(ScheduleCallback(base::FilePath()))); 557 RunTestCasesWithActiveItem(kCancelSaveAsTestCases, 558 arraysize(kCancelSaveAsTestCases)); 559 } 560 561 // The SafeBrowsing check is performed early. Make sure that a download item 562 // that has been marked as DANGEROUS_URL behaves correctly. 563 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_DangerousUrl) { 564 const DownloadTestCase kSafeBrowsingTestCases[] = { 565 { 566 // 0: Automatic Dangerous URL 567 AUTOMATIC, 568 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL, 569 "http://phishing.example.com/foo.txt", "", 570 FILE_PATH_LITERAL(""), 571 572 FILE_PATH_LITERAL(""), 573 FILE_PATH_LITERAL("foo.txt"), 574 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 575 576 EXPECT_UNCONFIRMED 577 }, 578 579 { 580 // 1: Save As Dangerous URL 581 SAVE_AS, 582 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL, 583 "http://phishing.example.com/foo.txt", "", 584 FILE_PATH_LITERAL(""), 585 586 FILE_PATH_LITERAL(""), 587 FILE_PATH_LITERAL("foo.txt"), 588 DownloadItem::TARGET_DISPOSITION_PROMPT, 589 590 EXPECT_UNCONFIRMED 591 }, 592 593 { 594 // 2: Forced Dangerous URL 595 FORCED, 596 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL, 597 "http://phishing.example.com/foo.txt", "", 598 FILE_PATH_LITERAL("forced-foo.txt"), 599 600 FILE_PATH_LITERAL(""), 601 FILE_PATH_LITERAL("forced-foo.txt"), 602 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 603 604 EXPECT_UNCONFIRMED 605 }, 606 607 { 608 // 3: Automatic Dangerous URL + Dangerous file. Dangerous URL takes 609 // precendence. 610 AUTOMATIC, 611 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL, 612 "http://phishing.example.com/foo.html", "", 613 FILE_PATH_LITERAL(""), 614 615 FILE_PATH_LITERAL(""), 616 FILE_PATH_LITERAL("foo.html"), 617 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 618 619 EXPECT_UNCONFIRMED 620 }, 621 622 { 623 // 4: Save As Dangerous URL + Dangerous file 624 SAVE_AS, 625 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL, 626 "http://phishing.example.com/foo.html", "", 627 FILE_PATH_LITERAL(""), 628 629 FILE_PATH_LITERAL(""), 630 FILE_PATH_LITERAL("foo.html"), 631 DownloadItem::TARGET_DISPOSITION_PROMPT, 632 633 EXPECT_UNCONFIRMED 634 }, 635 636 { 637 // 5: Forced Dangerous URL + Dangerous file 638 FORCED, 639 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL, 640 "http://phishing.example.com/foo.html", "", 641 FILE_PATH_LITERAL("forced-foo.html"), 642 643 FILE_PATH_LITERAL(""), 644 FILE_PATH_LITERAL("forced-foo.html"), 645 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 646 647 EXPECT_UNCONFIRMED 648 }, 649 }; 650 651 ON_CALL(*delegate(), CheckDownloadUrl(_, _, _)) 652 .WillByDefault(WithArg<2>(ScheduleCallback( 653 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL))); 654 RunTestCasesWithActiveItem(kSafeBrowsingTestCases, 655 arraysize(kSafeBrowsingTestCases)); 656 } 657 658 // The SafeBrowsing check is performed early. Make sure that a download item 659 // that has been marked as MAYBE_DANGEROUS_CONTENT behaves correctly. 660 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_MaybeDangerousContent) { 661 const DownloadTestCase kSafeBrowsingTestCases[] = { 662 { 663 // 0: Automatic Maybe dangerous content 664 AUTOMATIC, 665 content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT, 666 "http://phishing.example.com/foo.exe", "", 667 FILE_PATH_LITERAL(""), 668 669 FILE_PATH_LITERAL(""), 670 FILE_PATH_LITERAL("foo.exe"), 671 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 672 673 EXPECT_UNCONFIRMED 674 }, 675 676 { 677 // 1: Save As Maybe dangerous content 678 SAVE_AS, 679 content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT, 680 "http://phishing.example.com/foo.exe", "", 681 FILE_PATH_LITERAL(""), 682 683 FILE_PATH_LITERAL(""), 684 FILE_PATH_LITERAL("foo.exe"), 685 DownloadItem::TARGET_DISPOSITION_PROMPT, 686 687 EXPECT_UNCONFIRMED 688 }, 689 690 { 691 // 2: Forced Maybe dangerous content 692 FORCED, 693 content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT, 694 "http://phishing.example.com/foo.exe", "", 695 FILE_PATH_LITERAL("forced-foo.exe"), 696 697 FILE_PATH_LITERAL(""), 698 FILE_PATH_LITERAL("forced-foo.exe"), 699 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 700 701 EXPECT_UNCONFIRMED 702 }, 703 }; 704 705 ON_CALL(*delegate(), CheckDownloadUrl(_, _, _)) 706 .WillByDefault(WithArg<2>(ScheduleCallback( 707 content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT))); 708 RunTestCasesWithActiveItem(kSafeBrowsingTestCases, 709 arraysize(kSafeBrowsingTestCases)); 710 } 711 712 // Test whether the last saved directory is used for 'Save As' downloads. 713 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_LastSavePath) { 714 const DownloadTestCase kLastSavePathTestCasesPre[] = { 715 { 716 // 0: If the last save path is empty, then the default download directory 717 // should be used. 718 SAVE_AS, 719 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 720 "http://example.com/foo.txt", "text/plain", 721 FILE_PATH_LITERAL(""), 722 723 FILE_PATH_LITERAL(""), 724 FILE_PATH_LITERAL("foo.txt"), 725 DownloadItem::TARGET_DISPOSITION_PROMPT, 726 727 EXPECT_CRDOWNLOAD 728 } 729 }; 730 731 // These test cases are run with a last save path set to a non-emtpy local 732 // download directory. 733 const DownloadTestCase kLastSavePathTestCasesPost[] = { 734 { 735 // 0: This test case is run with the last download directory set to 736 // '<test_download_dir()>/foo'. 737 SAVE_AS, 738 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 739 "http://example.com/foo.txt", "text/plain", 740 FILE_PATH_LITERAL(""), 741 742 FILE_PATH_LITERAL(""), 743 FILE_PATH_LITERAL("foo/foo.txt"), 744 DownloadItem::TARGET_DISPOSITION_PROMPT, 745 746 EXPECT_CRDOWNLOAD 747 }, 748 749 { 750 // 1: Start an automatic download. This should be saved to the user's 751 // default download directory and not the last used Save As directory. 752 AUTOMATIC, 753 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 754 "http://example.com/foo.txt", "text/plain", 755 FILE_PATH_LITERAL(""), 756 757 FILE_PATH_LITERAL(""), 758 FILE_PATH_LITERAL("foo.txt"), 759 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 760 761 EXPECT_CRDOWNLOAD 762 }, 763 }; 764 765 // This test case is run with the last save path set to a non-empty virtual 766 // directory. 767 const DownloadTestCase kLastSavePathTestCasesVirtual[] = { 768 { 769 SAVE_AS, 770 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 771 "http://example.com/foo.txt", "text/plain", 772 FILE_PATH_LITERAL(""), 773 774 FILE_PATH_LITERAL("virtual/foo/foo.txt"), 775 FILE_PATH_LITERAL("bar.txt"), 776 DownloadItem::TARGET_DISPOSITION_PROMPT, 777 778 EXPECT_LOCAL_PATH 779 }, 780 }; 781 782 { 783 SCOPED_TRACE(testing::Message() 784 << "Running with default download path"); 785 base::FilePath prompt_path = 786 GetPathInDownloadDir(FILE_PATH_LITERAL("foo.txt")); 787 EXPECT_CALL(*delegate(), PromptUserForDownloadPath(_, prompt_path, _)); 788 RunTestCasesWithActiveItem(kLastSavePathTestCasesPre, 789 arraysize(kLastSavePathTestCasesPre)); 790 } 791 792 // Try with a non-empty last save path. 793 { 794 SCOPED_TRACE(testing::Message() 795 << "Running with local last_selected_directory"); 796 download_prefs()->SetSaveFilePath(test_download_dir().AppendASCII("foo")); 797 base::FilePath prompt_path = 798 GetPathInDownloadDir(FILE_PATH_LITERAL("foo/foo.txt")); 799 EXPECT_CALL(*delegate(), PromptUserForDownloadPath(_, prompt_path, _)); 800 RunTestCasesWithActiveItem(kLastSavePathTestCasesPost, 801 arraysize(kLastSavePathTestCasesPost)); 802 } 803 804 // And again, but this time use a virtual directory. 805 { 806 SCOPED_TRACE(testing::Message() 807 << "Running with virtual last_selected_directory"); 808 base::FilePath last_selected_dir = test_virtual_dir().AppendASCII("foo"); 809 base::FilePath virtual_path = last_selected_dir.AppendASCII("foo.txt"); 810 download_prefs()->SetSaveFilePath(last_selected_dir); 811 EXPECT_CALL(*delegate(), PromptUserForDownloadPath( 812 _, last_selected_dir.AppendASCII("foo.txt"), _)); 813 EXPECT_CALL(*delegate(), DetermineLocalPath(_, virtual_path, _)) 814 .WillOnce(WithArg<2>(ScheduleCallback( 815 GetPathInDownloadDir(FILE_PATH_LITERAL("bar.txt"))))); 816 RunTestCasesWithActiveItem(kLastSavePathTestCasesVirtual, 817 arraysize(kLastSavePathTestCasesVirtual)); 818 } 819 } 820 821 // These tests are run with the default downloads folder set to a virtual 822 // directory. 823 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_DefaultVirtual) { 824 // The default download directory is the virutal path. 825 download_prefs()->SetDownloadPath(test_virtual_dir()); 826 827 { 828 SCOPED_TRACE(testing::Message() << "Automatic Safe Download"); 829 const DownloadTestCase kAutomaticDownloadToVirtualDir = { 830 AUTOMATIC, 831 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 832 "http://example.com/foo.txt", "text/plain", 833 FILE_PATH_LITERAL(""), 834 835 // Downloaded to default virtual directory. 836 FILE_PATH_LITERAL("virtual/foo.txt"), 837 FILE_PATH_LITERAL("foo-local.txt"), 838 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 839 840 EXPECT_LOCAL_PATH 841 }; 842 EXPECT_CALL(*delegate(), DetermineLocalPath(_, _, _)) 843 .WillOnce(WithArg<2>(ScheduleCallback( 844 GetPathInDownloadDir(FILE_PATH_LITERAL("foo-local.txt"))))); 845 RunTestCasesWithActiveItem(&kAutomaticDownloadToVirtualDir, 1); 846 } 847 848 { 849 SCOPED_TRACE(testing::Message() << "Save As to virtual directory"); 850 const DownloadTestCase kSaveAsToVirtualDir = { 851 SAVE_AS, 852 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 853 "http://example.com/bar.txt", "text/plain", 854 FILE_PATH_LITERAL(""), 855 856 // The response to the download prompt is to choose the 'prompted.txt' 857 // virtual path. 858 FILE_PATH_LITERAL("virtual/prompted.txt"), 859 FILE_PATH_LITERAL("foo-local.txt"), 860 DownloadItem::TARGET_DISPOSITION_PROMPT, 861 862 EXPECT_LOCAL_PATH 863 }; 864 EXPECT_CALL(*delegate(), DetermineLocalPath(_, _, _)) 865 .WillOnce(WithArg<2>(ScheduleCallback( 866 GetPathInDownloadDir(FILE_PATH_LITERAL("foo-local.txt"))))); 867 EXPECT_CALL(*delegate(), PromptUserForDownloadPath( 868 _, test_virtual_dir().AppendASCII("bar.txt"), _)) 869 .WillOnce(WithArg<2>(ScheduleCallback( 870 test_virtual_dir().AppendASCII("prompted.txt")))); 871 RunTestCasesWithActiveItem(&kSaveAsToVirtualDir, 1); 872 } 873 874 { 875 SCOPED_TRACE(testing::Message() << "Save As to local directory"); 876 const DownloadTestCase kSaveAsToLocalDir = { 877 SAVE_AS, 878 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 879 "http://example.com/bar.txt", "text/plain", 880 FILE_PATH_LITERAL(""), 881 882 // Response to the 'Save As' is to choose the local path for 'foo-x.txt'. 883 FILE_PATH_LITERAL(""), 884 FILE_PATH_LITERAL("foo-x.txt"), 885 DownloadItem::TARGET_DISPOSITION_PROMPT, 886 887 EXPECT_CRDOWNLOAD 888 }; 889 EXPECT_CALL(*delegate(), PromptUserForDownloadPath( 890 _, test_virtual_dir().AppendASCII("bar.txt"), _)) 891 .WillOnce(WithArg<2>(ScheduleCallback( 892 GetPathInDownloadDir(FILE_PATH_LITERAL("foo-x.txt"))))); 893 RunTestCasesWithActiveItem(&kSaveAsToLocalDir, 1); 894 } 895 896 { 897 SCOPED_TRACE(testing::Message() << "Forced safe download"); 898 const DownloadTestCase kForcedSafe = { 899 FORCED, 900 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 901 "http://example.com/foo.txt", "", 902 FILE_PATH_LITERAL("forced-foo.txt"), 903 904 // Forced paths should be left as-is. 905 FILE_PATH_LITERAL(""), 906 FILE_PATH_LITERAL("forced-foo.txt"), 907 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 908 909 EXPECT_LOCAL_PATH 910 }; 911 RunTestCasesWithActiveItem(&kForcedSafe, 1); 912 } 913 } 914 915 // Test that an inactive download will still get a virtual or local download 916 // path. 917 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_InactiveDownload) { 918 const DownloadTestCase kInactiveTestCases[] = { 919 { 920 AUTOMATIC, 921 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 922 "http://example.com/foo.txt", "text/plain", 923 FILE_PATH_LITERAL(""), 924 925 FILE_PATH_LITERAL("foo.txt"), 926 FILE_PATH_LITERAL(""), 927 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 928 929 EXPECT_LOCAL_PATH 930 }, 931 932 { 933 SAVE_AS, 934 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 935 "http://example.com/foo.txt", "text/plain", 936 FILE_PATH_LITERAL(""), 937 938 FILE_PATH_LITERAL("foo.txt"), 939 FILE_PATH_LITERAL(""), 940 DownloadItem::TARGET_DISPOSITION_PROMPT, 941 942 EXPECT_LOCAL_PATH 943 } 944 }; 945 946 for (size_t i = 0; i < arraysize(kInactiveTestCases); ++i) { 947 SCOPED_TRACE(testing::Message() << "Running test case " << i); 948 const DownloadTestCase& test_case = kInactiveTestCases[i]; 949 scoped_ptr<content::MockDownloadItem> item( 950 CreateActiveDownloadItem(i, test_case)); 951 EXPECT_CALL(*item.get(), GetState()) 952 .WillRepeatedly(Return(content::DownloadItem::CANCELLED)); 953 // Even though one is a SAVE_AS download, no prompt will be displayed to 954 // the user because the download is inactive. 955 EXPECT_CALL(*delegate(), PromptUserForDownloadPath(_, _, _)) 956 .Times(0); 957 RunTestCase(test_case, base::FilePath(), item.get()); 958 } 959 } 960 961 // If the reserved path could not be verified, then the user should see a 962 // prompt. 963 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_ReservationFailed) { 964 const DownloadTestCase kReservationFailedCases[] = { 965 { 966 // 0: Automatic download. Since the reservation fails, the disposition of 967 // the target is to prompt, but the returned path is used. 968 AUTOMATIC, 969 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 970 "http://example.com/foo.txt", "text/plain", 971 FILE_PATH_LITERAL(""), 972 973 FILE_PATH_LITERAL(""), 974 FILE_PATH_LITERAL("bar.txt"), 975 DownloadItem::TARGET_DISPOSITION_PROMPT, 976 977 EXPECT_CRDOWNLOAD 978 }, 979 }; 980 981 // Setup ReserveVirtualPath() to fail. 982 ON_CALL(*delegate(), ReserveVirtualPath(_, _, _, _, _)) 983 .WillByDefault(WithArg<4>(ScheduleCallback2( 984 GetPathInDownloadDir(FILE_PATH_LITERAL("bar.txt")), false))); 985 RunTestCasesWithActiveItem(kReservationFailedCases, 986 arraysize(kReservationFailedCases)); 987 } 988 989 // If the local path could not be determined, the download should be cancelled. 990 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_LocalPathFailed) { 991 const DownloadTestCase kLocalPathFailedCases[] = { 992 { 993 // 0: Automatic download. 994 AUTOMATIC, 995 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 996 "http://example.com/foo.txt", "text/plain", 997 FILE_PATH_LITERAL(""), 998 999 FILE_PATH_LITERAL(""), 1000 FILE_PATH_LITERAL(""), 1001 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 1002 1003 EXPECT_LOCAL_PATH 1004 }, 1005 }; 1006 1007 base::FilePath expected_virtual_path( 1008 GetPathInDownloadDir(FILE_PATH_LITERAL("virtual/foo.txt"))); 1009 // The default download directory is the virtual path. 1010 download_prefs()->SetDownloadPath(test_virtual_dir()); 1011 // Simulate failed call to DetermineLocalPath. 1012 EXPECT_CALL(*delegate(), DetermineLocalPath( 1013 _, GetPathInDownloadDir(FILE_PATH_LITERAL("virtual/foo.txt")), _)) 1014 .WillOnce(WithArg<2>(ScheduleCallback(base::FilePath()))); 1015 RunTestCasesWithActiveItem(kLocalPathFailedCases, 1016 arraysize(kLocalPathFailedCases)); 1017 } 1018 1019 // Downloads that have a danger level of ALLOW_ON_USER_GESTURE should be marked 1020 // as safe depending on whether there was a user gesture associated with the 1021 // download and whether the referrer was visited prior to today. 1022 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_VisitedReferrer) { 1023 const DownloadTestCase kVisitedReferrerCases[] = { 1024 // http://visited.example.com/ is added to the history as a visit that 1025 // happened prior to today. 1026 { 1027 // 0: Safe download due to visiting referrer before. 1028 AUTOMATIC, 1029 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 1030 "http://visited.example.com/foo.html", "text/html", 1031 FILE_PATH_LITERAL(""), 1032 1033 FILE_PATH_LITERAL(""), 1034 FILE_PATH_LITERAL("foo.html"), 1035 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 1036 1037 EXPECT_CRDOWNLOAD 1038 }, 1039 1040 { 1041 // 1: Dangerous due to not having visited referrer before. 1042 AUTOMATIC, 1043 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE, 1044 "http://not-visited.example.com/foo.html", "text/html", 1045 FILE_PATH_LITERAL(""), 1046 1047 FILE_PATH_LITERAL(""), 1048 FILE_PATH_LITERAL("foo.html"), 1049 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 1050 1051 EXPECT_UNCONFIRMED 1052 }, 1053 1054 { 1055 // 2: Safe because the user is being prompted. 1056 SAVE_AS, 1057 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 1058 "http://not-visited.example.com/foo.html", "text/html", 1059 FILE_PATH_LITERAL(""), 1060 1061 FILE_PATH_LITERAL(""), 1062 FILE_PATH_LITERAL("foo.html"), 1063 DownloadItem::TARGET_DISPOSITION_PROMPT, 1064 1065 EXPECT_CRDOWNLOAD 1066 }, 1067 1068 { 1069 // 3: Safe because of forced path. 1070 FORCED, 1071 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 1072 "http://not-visited.example.com/foo.html", "text/html", 1073 FILE_PATH_LITERAL("foo.html"), 1074 1075 FILE_PATH_LITERAL(""), 1076 FILE_PATH_LITERAL("foo.html"), 1077 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 1078 1079 EXPECT_LOCAL_PATH 1080 }, 1081 }; 1082 1083 // This test assumes that the danger level of .html files is 1084 // ALLOW_ON_USER_GESTURE. 1085 ASSERT_EQ(download_util::ALLOW_ON_USER_GESTURE, 1086 download_util::GetFileDangerLevel( 1087 base::FilePath(FILE_PATH_LITERAL("foo.html")))); 1088 1089 // First the history service must exist. 1090 ASSERT_TRUE(profile()->CreateHistoryService(false, false)); 1091 1092 GURL url("http://visited.example.com/visited-link.html"); 1093 // The time of visit is picked to be several seconds prior to the most recent 1094 // midnight. 1095 base::Time time_of_visit( 1096 base::Time::Now().LocalMidnight() - base::TimeDelta::FromSeconds(10)); 1097 HistoryService* history_service = 1098 HistoryServiceFactory::GetForProfile(profile(), Profile::EXPLICIT_ACCESS); 1099 ASSERT_TRUE(history_service); 1100 history_service->AddPage(url, time_of_visit, history::SOURCE_BROWSED); 1101 1102 RunTestCasesWithActiveItem(kVisitedReferrerCases, 1103 arraysize(kVisitedReferrerCases)); 1104 } 1105 1106 // These test cases are run with "Prompt for download" user preference set to 1107 // true. 1108 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_PromptAlways) { 1109 const DownloadTestCase kPromptingTestCases[] = { 1110 { 1111 // 0: Safe Automatic - Should prompt because of "Prompt for download" 1112 // preference setting. 1113 AUTOMATIC, 1114 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 1115 "http://example.com/foo.txt", "text/plain", 1116 FILE_PATH_LITERAL(""), 1117 1118 FILE_PATH_LITERAL(""), 1119 FILE_PATH_LITERAL("foo.txt"), 1120 DownloadItem::TARGET_DISPOSITION_PROMPT, 1121 1122 EXPECT_CRDOWNLOAD 1123 }, 1124 1125 { 1126 // 1: Safe Forced - Shouldn't prompt. 1127 FORCED, 1128 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 1129 "http://example.com/foo.txt", "text/plain", 1130 FILE_PATH_LITERAL("foo.txt"), 1131 1132 FILE_PATH_LITERAL(""), 1133 FILE_PATH_LITERAL("foo.txt"), 1134 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 1135 1136 EXPECT_LOCAL_PATH 1137 }, 1138 1139 { 1140 // 2: Automatic - The filename extension is marked as one that we will 1141 // open automatically. Shouldn't prompt. 1142 AUTOMATIC, 1143 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 1144 "http://example.com/foo.dummy", "", 1145 FILE_PATH_LITERAL(""), 1146 1147 FILE_PATH_LITERAL(""), 1148 FILE_PATH_LITERAL("foo.dummy"), 1149 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 1150 1151 EXPECT_CRDOWNLOAD 1152 }, 1153 }; 1154 1155 SetPromptForDownload(true); 1156 EnableAutoOpenBasedOnExtension( 1157 base::FilePath(FILE_PATH_LITERAL("dummy.dummy"))); 1158 RunTestCasesWithActiveItem(kPromptingTestCases, 1159 arraysize(kPromptingTestCases)); 1160 } 1161 1162 #if !defined(OS_ANDROID) 1163 // These test cases are run with "Prompt for download" user preference set to 1164 // true. Automatic extension downloads shouldn't cause prompting. 1165 // Android doesn't support extensions. 1166 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_PromptAlways_Extension) { 1167 const DownloadTestCase kPromptingTestCases[] = { 1168 { 1169 // 0: Automatic Browser Extension download. - Shouldn't prompt for browser 1170 // extension downloads even if "Prompt for download" preference is set. 1171 AUTOMATIC, 1172 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE, 1173 "http://example.com/foo.crx", 1174 extensions::Extension::kMimeType, 1175 FILE_PATH_LITERAL(""), 1176 1177 FILE_PATH_LITERAL(""), 1178 FILE_PATH_LITERAL("foo.crx"), 1179 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 1180 1181 EXPECT_UNCONFIRMED 1182 }, 1183 1184 #if defined(OS_WIN) 1185 { 1186 // 1: Automatic User Script - Shouldn't prompt for user script downloads 1187 // even if "Prompt for download" preference is set. ".js" files are 1188 // considered dangerous on Windows. 1189 AUTOMATIC, 1190 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE, 1191 "http://example.com/foo.user.js", "", 1192 FILE_PATH_LITERAL(""), 1193 1194 FILE_PATH_LITERAL(""), 1195 FILE_PATH_LITERAL("foo.user.js"), 1196 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 1197 1198 EXPECT_UNCONFIRMED 1199 }, 1200 #else 1201 { 1202 // 1: Automatic User Script - Shouldn't prompt for user script downloads 1203 // even if "Prompt for download" preference is set. 1204 AUTOMATIC, 1205 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 1206 "http://example.com/foo.user.js", "", 1207 FILE_PATH_LITERAL(""), 1208 1209 FILE_PATH_LITERAL(""), 1210 FILE_PATH_LITERAL("foo.user.js"), 1211 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 1212 1213 EXPECT_CRDOWNLOAD 1214 }, 1215 #endif 1216 }; 1217 1218 SetPromptForDownload(true); 1219 RunTestCasesWithActiveItem(kPromptingTestCases, 1220 arraysize(kPromptingTestCases)); 1221 } 1222 #endif 1223 1224 // If the download path is managed, then we don't show any prompts. 1225 // Note that if the download path is managed, then PromptForDownload() is false. 1226 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_ManagedPath) { 1227 const DownloadTestCase kManagedPathTestCases[] = { 1228 { 1229 // 0: Automatic Safe 1230 AUTOMATIC, 1231 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 1232 "http://example.com/foo.txt", "text/plain", 1233 FILE_PATH_LITERAL(""), 1234 1235 FILE_PATH_LITERAL(""), 1236 FILE_PATH_LITERAL("foo.txt"), 1237 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 1238 1239 EXPECT_CRDOWNLOAD 1240 }, 1241 1242 { 1243 // 1: Save_As Safe 1244 SAVE_AS, 1245 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 1246 "http://example.com/foo.txt", "text/plain", 1247 FILE_PATH_LITERAL(""), 1248 1249 FILE_PATH_LITERAL(""), 1250 FILE_PATH_LITERAL("foo.txt"), 1251 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 1252 1253 EXPECT_CRDOWNLOAD 1254 }, 1255 }; 1256 1257 SetManagedDownloadPath(test_download_dir()); 1258 ASSERT_TRUE(download_prefs()->IsDownloadPathManaged()); 1259 RunTestCasesWithActiveItem(kManagedPathTestCases, 1260 arraysize(kManagedPathTestCases)); 1261 } 1262 1263 // Test basic functionality supporting extensions that want to override download 1264 // filenames. 1265 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_NotifyExtensionsSafe) { 1266 const DownloadTestCase kNotifyExtensionsTestCases[] = { 1267 { 1268 // 0: Automatic Safe 1269 AUTOMATIC, 1270 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 1271 "http://example.com/foo.txt", "text/plain", 1272 FILE_PATH_LITERAL(""), 1273 1274 FILE_PATH_LITERAL(""), 1275 FILE_PATH_LITERAL("overridden/foo.txt"), 1276 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 1277 1278 EXPECT_CRDOWNLOAD 1279 }, 1280 1281 { 1282 // 1: Save_As Safe 1283 SAVE_AS, 1284 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 1285 "http://example.com/foo.txt", "text/plain", 1286 FILE_PATH_LITERAL(""), 1287 1288 FILE_PATH_LITERAL(""), 1289 FILE_PATH_LITERAL("overridden/foo.txt"), 1290 DownloadItem::TARGET_DISPOSITION_PROMPT, 1291 1292 EXPECT_CRDOWNLOAD 1293 }, 1294 1295 { 1296 // 2: Automatic Dangerous 1297 AUTOMATIC, 1298 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE, 1299 "http://example.com/foo.html", "", 1300 FILE_PATH_LITERAL(""), 1301 1302 FILE_PATH_LITERAL(""), 1303 FILE_PATH_LITERAL("overridden/foo.html"), 1304 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 1305 1306 EXPECT_UNCONFIRMED 1307 }, 1308 1309 { 1310 // 3: Forced Safe 1311 FORCED, 1312 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 1313 "http://example.com/foo.txt", "", 1314 FILE_PATH_LITERAL("forced-foo.txt"), 1315 1316 FILE_PATH_LITERAL(""), 1317 FILE_PATH_LITERAL("forced-foo.txt"), 1318 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 1319 1320 EXPECT_LOCAL_PATH 1321 }, 1322 }; 1323 1324 ON_CALL(*delegate(), NotifyExtensions(_, _, _)) 1325 .WillByDefault(Invoke(&NotifyExtensionsOverridePath)); 1326 RunTestCasesWithActiveItem(kNotifyExtensionsTestCases, 1327 arraysize(kNotifyExtensionsTestCases)); 1328 } 1329 1330 // Test that filenames provided by extensions are passed into SafeBrowsing 1331 // checks and dangerous download checks. 1332 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_NotifyExtensionsUnsafe) { 1333 const DownloadTestCase kNotifyExtensionsTestCases[] = { 1334 { 1335 // 0: Automatic Safe : Later overridden by a dangerous filetype. 1336 AUTOMATIC, 1337 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE, 1338 "http://example.com/foo.html.remove", "text/plain", 1339 FILE_PATH_LITERAL(""), 1340 1341 FILE_PATH_LITERAL(""), 1342 FILE_PATH_LITERAL("overridden/foo.html"), 1343 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 1344 1345 EXPECT_UNCONFIRMED 1346 }, 1347 1348 { 1349 // 1: Automatic Safe : Later overridden by a potentially dangerous 1350 // filetype. 1351 AUTOMATIC, 1352 content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT, 1353 "http://example.com/foo.exe.remove", "text/plain", 1354 FILE_PATH_LITERAL(""), 1355 1356 FILE_PATH_LITERAL(""), 1357 FILE_PATH_LITERAL("overridden/foo.exe"), 1358 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 1359 1360 EXPECT_UNCONFIRMED 1361 }, 1362 }; 1363 1364 ON_CALL(*delegate(), NotifyExtensions(_, _, _)) 1365 .WillByDefault(Invoke(&NotifyExtensionsOverridePath)); 1366 ON_CALL(*delegate(), CheckDownloadUrl(_, _, _)) 1367 .WillByDefault(Invoke(&CheckDownloadUrlCheckExes)); 1368 RunTestCasesWithActiveItem(kNotifyExtensionsTestCases, 1369 arraysize(kNotifyExtensionsTestCases)); 1370 } 1371 1372 // Test that conflict actions set by extensions are passed correctly into 1373 // ReserveVirtualPath. 1374 TEST_F(DownloadTargetDeterminerTest, 1375 TargetDeterminer_NotifyExtensionsConflict) { 1376 const DownloadTestCase kNotifyExtensionsTestCase = { 1377 AUTOMATIC, 1378 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 1379 "http://example.com/foo.txt", "text/plain", 1380 FILE_PATH_LITERAL(""), 1381 1382 FILE_PATH_LITERAL(""), 1383 FILE_PATH_LITERAL("overridden/foo.txt"), 1384 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 1385 1386 EXPECT_CRDOWNLOAD 1387 }; 1388 1389 const DownloadTestCase& test_case = kNotifyExtensionsTestCase; 1390 scoped_ptr<content::MockDownloadItem> item( 1391 CreateActiveDownloadItem(0, test_case)); 1392 base::FilePath overridden_path(FILE_PATH_LITERAL("overridden/foo.txt")); 1393 base::FilePath full_overridden_path = 1394 GetPathInDownloadDir(overridden_path.value()); 1395 1396 // First case: An extension sets the conflict_action to OVERWRITE. 1397 EXPECT_CALL(*delegate(), NotifyExtensions(_, _, _)) 1398 .WillOnce(WithArg<2>( 1399 ScheduleCallback2(overridden_path, 1400 DownloadPathReservationTracker::OVERWRITE))); 1401 EXPECT_CALL(*delegate(), ReserveVirtualPath( 1402 _, full_overridden_path, true, DownloadPathReservationTracker::OVERWRITE, 1403 _)).WillOnce(WithArg<4>( 1404 ScheduleCallback2(full_overridden_path, true))); 1405 1406 RunTestCase(test_case, base::FilePath(), item.get()); 1407 1408 // Second case: An extension sets the conflict_action to PROMPT. 1409 EXPECT_CALL(*delegate(), NotifyExtensions(_, _, _)) 1410 .WillOnce(WithArg<2>( 1411 ScheduleCallback2(overridden_path, 1412 DownloadPathReservationTracker::PROMPT))); 1413 EXPECT_CALL(*delegate(), ReserveVirtualPath( 1414 _, full_overridden_path, true, DownloadPathReservationTracker::PROMPT, _)) 1415 .WillOnce(WithArg<4>( 1416 ScheduleCallback2(full_overridden_path, true))); 1417 RunTestCase(test_case, base::FilePath(), item.get()); 1418 } 1419 1420 // Test that relative paths returned by extensions are always relative to the 1421 // default downloads path. 1422 TEST_F(DownloadTargetDeterminerTest, 1423 TargetDeterminer_NotifyExtensionsDefaultPath) { 1424 const DownloadTestCase kNotifyExtensionsTestCase = { 1425 SAVE_AS, 1426 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 1427 "http://example.com/foo.txt", "text/plain", 1428 FILE_PATH_LITERAL(""), 1429 1430 FILE_PATH_LITERAL(""), 1431 FILE_PATH_LITERAL("overridden/foo.txt"), 1432 DownloadItem::TARGET_DISPOSITION_PROMPT, 1433 1434 EXPECT_CRDOWNLOAD 1435 }; 1436 1437 const DownloadTestCase& test_case = kNotifyExtensionsTestCase; 1438 scoped_ptr<content::MockDownloadItem> item( 1439 CreateActiveDownloadItem(0, test_case)); 1440 base::FilePath overridden_path(FILE_PATH_LITERAL("overridden/foo.txt")); 1441 base::FilePath full_overridden_path = 1442 GetPathInDownloadDir(overridden_path.value()); 1443 1444 download_prefs()->SetSaveFilePath(GetPathInDownloadDir( 1445 FILE_PATH_LITERAL("last_selected"))); 1446 1447 EXPECT_CALL(*delegate(), NotifyExtensions(_, _, _)) 1448 .WillOnce(WithArg<2>( 1449 ScheduleCallback2(overridden_path, 1450 DownloadPathReservationTracker::UNIQUIFY))); 1451 EXPECT_CALL(*delegate(), 1452 PromptUserForDownloadPath(_, full_overridden_path, _)) 1453 .WillOnce(WithArg<2>( 1454 ScheduleCallback(full_overridden_path))); 1455 RunTestCase(test_case, base::FilePath(), item.get()); 1456 } 1457 1458 TEST_F(DownloadTargetDeterminerTest, 1459 TargetDeterminer_InitialVirtualPathUnsafe) { 1460 const base::FilePath::CharType* kInitialPath = 1461 FILE_PATH_LITERAL("some_path/bar.html"); 1462 1463 const DownloadTestCase kInitialPathTestCase = { 1464 // 0: Save As Save. The path generated based on the DownloadItem is safe, 1465 // but the initial path is unsafe. However, the download is not considered 1466 // dangerous since the user has been prompted. 1467 SAVE_AS, 1468 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 1469 "http://example.com/foo.txt", "text/plain", 1470 FILE_PATH_LITERAL(""), 1471 1472 FILE_PATH_LITERAL(""), 1473 kInitialPath, 1474 DownloadItem::TARGET_DISPOSITION_PROMPT, 1475 1476 EXPECT_CRDOWNLOAD 1477 }; 1478 1479 const DownloadTestCase& test_case = kInitialPathTestCase; 1480 scoped_ptr<content::MockDownloadItem> item( 1481 CreateActiveDownloadItem(1, test_case)); 1482 EXPECT_CALL(*item, GetLastReason()) 1483 .WillRepeatedly(Return( 1484 content::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED)); 1485 EXPECT_CALL(*item, GetTargetDisposition()) 1486 .WillRepeatedly(Return(DownloadItem::TARGET_DISPOSITION_PROMPT)); 1487 RunTestCase(test_case, GetPathInDownloadDir(kInitialPath), item.get()); 1488 } 1489 1490 // Prompting behavior for resumed downloads is based on the last interrupt 1491 // reason. If the reason indicates that the target path may not be suitable for 1492 // the download (ACCESS_DENIED, NO_SPACE, etc..), then the user should be 1493 // prompted, and not otherwise. These test cases shouldn't result in prompting 1494 // since the error is set to NETWORK_FAILED. 1495 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_ResumedNoPrompt) { 1496 // All test cases run with GetPathInDownloadDir(kInitialPath) as the inital 1497 // path. 1498 const base::FilePath::CharType* kInitialPath = 1499 FILE_PATH_LITERAL("some_path/bar.txt"); 1500 1501 const DownloadTestCase kResumedTestCases[] = { 1502 { 1503 // 0: Automatic Safe: Initial path is ignored since the user has not been 1504 // prompted before. 1505 AUTOMATIC, 1506 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 1507 "http://example.com/foo.txt", "text/plain", 1508 FILE_PATH_LITERAL(""), 1509 1510 FILE_PATH_LITERAL(""), 1511 FILE_PATH_LITERAL("foo.txt"), 1512 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 1513 1514 EXPECT_CRDOWNLOAD 1515 }, 1516 1517 { 1518 // 1: Save_As Safe: Initial path used. 1519 SAVE_AS, 1520 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 1521 "http://example.com/foo.txt", "text/plain", 1522 FILE_PATH_LITERAL(""), 1523 1524 FILE_PATH_LITERAL(""), 1525 kInitialPath, 1526 DownloadItem::TARGET_DISPOSITION_PROMPT, 1527 1528 EXPECT_CRDOWNLOAD 1529 }, 1530 1531 { 1532 // 2: Automatic Dangerous: Initial path is ignored since the user hasn't 1533 // been prompted before. 1534 AUTOMATIC, 1535 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE, 1536 "http://example.com/foo.html", "", 1537 FILE_PATH_LITERAL(""), 1538 1539 FILE_PATH_LITERAL(""), 1540 FILE_PATH_LITERAL("foo.html"), 1541 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 1542 1543 EXPECT_UNCONFIRMED 1544 }, 1545 1546 { 1547 // 3: Forced Safe: Initial path is ignored due to the forced path. 1548 FORCED, 1549 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 1550 "http://example.com/foo.txt", "", 1551 FILE_PATH_LITERAL("forced-foo.txt"), 1552 1553 FILE_PATH_LITERAL(""), 1554 FILE_PATH_LITERAL("forced-foo.txt"), 1555 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 1556 1557 EXPECT_LOCAL_PATH 1558 }, 1559 }; 1560 1561 // The test assumes that .html files have a danger level of 1562 // ALLOW_ON_USER_GESTURE. 1563 ASSERT_EQ(download_util::ALLOW_ON_USER_GESTURE, 1564 download_util::GetFileDangerLevel( 1565 base::FilePath(FILE_PATH_LITERAL("foo.html")))); 1566 for (size_t i = 0; i < arraysize(kResumedTestCases); ++i) { 1567 SCOPED_TRACE(testing::Message() << "Running test case " << i); 1568 const DownloadTestCase& test_case = kResumedTestCases[i]; 1569 scoped_ptr<content::MockDownloadItem> item( 1570 CreateActiveDownloadItem(i, test_case)); 1571 base::FilePath expected_path = 1572 GetPathInDownloadDir(test_case.expected_local_path); 1573 ON_CALL(*item.get(), GetLastReason()) 1574 .WillByDefault(Return( 1575 content::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED)); 1576 // Extensions should be notified if a new path is being generated and there 1577 // is no forced path. In the test cases above, this is true for tests with 1578 // type == AUTOMATIC. 1579 EXPECT_CALL(*delegate(), NotifyExtensions(_, _, _)) 1580 .Times(test_case.test_type == AUTOMATIC ? 1 : 0); 1581 EXPECT_CALL(*delegate(), ReserveVirtualPath(_, expected_path, false, _, _)); 1582 EXPECT_CALL(*delegate(), PromptUserForDownloadPath(_, expected_path, _)) 1583 .Times(0); 1584 EXPECT_CALL(*delegate(), DetermineLocalPath(_, expected_path, _)); 1585 EXPECT_CALL(*delegate(), CheckDownloadUrl(_, expected_path, _)); 1586 RunTestCase(test_case, GetPathInDownloadDir(kInitialPath), item.get()); 1587 } 1588 1589 } 1590 1591 // Test that a forced download doesn't prompt, even if the interrupt reason 1592 // suggests that the target path may not be suitable for downloads. 1593 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_ResumedForcedDownload) { 1594 const base::FilePath::CharType* kInitialPath = 1595 FILE_PATH_LITERAL("some_path/bar.txt"); 1596 const DownloadTestCase kResumedForcedDownload = { 1597 // 3: Forced Safe 1598 FORCED, 1599 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 1600 "http://example.com/foo.txt", "", 1601 FILE_PATH_LITERAL("forced-foo.txt"), 1602 1603 FILE_PATH_LITERAL(""), 1604 FILE_PATH_LITERAL("forced-foo.txt"), 1605 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 1606 1607 EXPECT_LOCAL_PATH 1608 }; 1609 1610 const DownloadTestCase& test_case = kResumedForcedDownload; 1611 base::FilePath expected_path = 1612 GetPathInDownloadDir(test_case.expected_local_path); 1613 scoped_ptr<content::MockDownloadItem> item( 1614 CreateActiveDownloadItem(0, test_case)); 1615 ON_CALL(*item.get(), GetLastReason()) 1616 .WillByDefault(Return(content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE)); 1617 EXPECT_CALL(*delegate(), NotifyExtensions(_, _, _)) 1618 .Times(test_case.test_type == AUTOMATIC ? 1 : 0); 1619 EXPECT_CALL(*delegate(), ReserveVirtualPath(_, expected_path, false, _, _)); 1620 EXPECT_CALL(*delegate(), PromptUserForDownloadPath(_, _, _)) 1621 .Times(0); 1622 EXPECT_CALL(*delegate(), DetermineLocalPath(_, expected_path, _)); 1623 EXPECT_CALL(*delegate(), CheckDownloadUrl(_, expected_path, _)); 1624 RunTestCase(test_case, GetPathInDownloadDir(kInitialPath), item.get()); 1625 } 1626 1627 // Prompting behavior for resumed downloads is based on the last interrupt 1628 // reason. If the reason indicates that the target path may not be suitable for 1629 // the download (ACCESS_DENIED, NO_SPACE, etc..), then the user should be 1630 // prompted, and not otherwise. These test cases result in prompting since the 1631 // error is set to NO_SPACE. 1632 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_ResumedWithPrompt) { 1633 // All test cases run with GetPathInDownloadDir(kInitialPath) as the inital 1634 // path. 1635 const base::FilePath::CharType* kInitialPath = 1636 FILE_PATH_LITERAL("some_path/bar.txt"); 1637 1638 const DownloadTestCase kResumedTestCases[] = { 1639 { 1640 // 0: Automatic Safe 1641 AUTOMATIC, 1642 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 1643 "http://example.com/foo.txt", "text/plain", 1644 FILE_PATH_LITERAL(""), 1645 1646 FILE_PATH_LITERAL(""), 1647 FILE_PATH_LITERAL("foo.txt"), 1648 DownloadItem::TARGET_DISPOSITION_PROMPT, 1649 1650 EXPECT_CRDOWNLOAD 1651 }, 1652 1653 { 1654 // 1: Save_As Safe 1655 SAVE_AS, 1656 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 1657 "http://example.com/foo.txt", "text/plain", 1658 FILE_PATH_LITERAL(""), 1659 1660 FILE_PATH_LITERAL(""), 1661 kInitialPath, 1662 DownloadItem::TARGET_DISPOSITION_PROMPT, 1663 1664 EXPECT_CRDOWNLOAD 1665 }, 1666 1667 { 1668 // 2: Automatic Dangerous 1669 AUTOMATIC, 1670 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 1671 "http://example.com/foo.html", "", 1672 FILE_PATH_LITERAL(""), 1673 1674 FILE_PATH_LITERAL(""), 1675 FILE_PATH_LITERAL("foo.html"), 1676 DownloadItem::TARGET_DISPOSITION_PROMPT, 1677 1678 EXPECT_CRDOWNLOAD 1679 }, 1680 }; 1681 1682 // The test assumes that .html files have a danger level of 1683 // ALLOW_ON_USER_GESTURE. 1684 ASSERT_EQ(download_util::ALLOW_ON_USER_GESTURE, 1685 download_util::GetFileDangerLevel( 1686 base::FilePath(FILE_PATH_LITERAL("foo.html")))); 1687 for (size_t i = 0; i < arraysize(kResumedTestCases); ++i) { 1688 SCOPED_TRACE(testing::Message() << "Running test case " << i); 1689 download_prefs()->SetSaveFilePath(test_download_dir()); 1690 const DownloadTestCase& test_case = kResumedTestCases[i]; 1691 base::FilePath expected_path = 1692 GetPathInDownloadDir(test_case.expected_local_path); 1693 scoped_ptr<content::MockDownloadItem> item( 1694 CreateActiveDownloadItem(i, test_case)); 1695 ON_CALL(*item.get(), GetLastReason()) 1696 .WillByDefault(Return( 1697 content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE)); 1698 EXPECT_CALL(*delegate(), NotifyExtensions(_, _, _)) 1699 .Times(test_case.test_type == AUTOMATIC ? 1 : 0); 1700 EXPECT_CALL(*delegate(), ReserveVirtualPath(_, expected_path, false, _, _)); 1701 EXPECT_CALL(*delegate(), PromptUserForDownloadPath(_, expected_path, _)); 1702 EXPECT_CALL(*delegate(), DetermineLocalPath(_, expected_path, _)); 1703 EXPECT_CALL(*delegate(), CheckDownloadUrl(_, expected_path, _)); 1704 RunTestCase(test_case, GetPathInDownloadDir(kInitialPath), item.get()); 1705 } 1706 } 1707 1708 // Used with TargetDeterminer_IntermediateNameForResumed test. Verifies that 1709 // |intermediate_path| == |expected_intermediate_path| if the latter is 1710 // non-empty. 1711 void IntermediatePathVerifier( 1712 const base::FilePath& expected_intermediate_path, 1713 const content::DownloadTargetCallback& callback, 1714 const base::FilePath& target_path, 1715 content::DownloadItem::TargetDisposition disposition, 1716 content::DownloadDangerType danger_type, 1717 const base::FilePath& intermediate_path) { 1718 if (!expected_intermediate_path.empty()) 1719 EXPECT_EQ(expected_intermediate_path, intermediate_path); 1720 callback.Run(target_path, disposition, danger_type, intermediate_path); 1721 } 1722 1723 // Test intermediate filename generation for resumed downloads. 1724 TEST_F(DownloadTargetDeterminerTest, 1725 TargetDeterminer_IntermediateNameForResumed) { 1726 // All test cases run with GetPathInDownloadDir(kInitialPath) as the inital 1727 // path. 1728 const base::FilePath::CharType kInitialPath[] = 1729 FILE_PATH_LITERAL("some_path/bar.txt"); 1730 1731 struct IntermediateNameTestCase { 1732 // General test case settings. 1733 DownloadTestCase general; 1734 1735 // Value of DownloadItem::GetFullPath() during test run, relative 1736 // to test download path. 1737 const base::FilePath::CharType* initial_intermediate_path; 1738 1739 // Expected intermediate path relatvie to the test download path. An exact 1740 // match is performed if this string is non-empty. Ignored otherwise. 1741 const base::FilePath::CharType* expected_intermediate_path; 1742 } kIntermediateNameTestCases[] = { 1743 { 1744 { 1745 // 0: Automatic Safe 1746 AUTOMATIC, 1747 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 1748 "http://example.com/foo.txt", "text/plain", 1749 FILE_PATH_LITERAL(""), 1750 1751 FILE_PATH_LITERAL(""), 1752 FILE_PATH_LITERAL("foo.txt"), 1753 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 1754 1755 EXPECT_CRDOWNLOAD 1756 }, 1757 FILE_PATH_LITERAL("bar.txt.crdownload"), 1758 FILE_PATH_LITERAL("foo.txt.crdownload") 1759 }, 1760 1761 { 1762 { 1763 // 1: Save_As Safe 1764 SAVE_AS, 1765 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 1766 "http://example.com/foo.txt", "text/plain", 1767 FILE_PATH_LITERAL(""), 1768 1769 FILE_PATH_LITERAL(""), 1770 kInitialPath, 1771 DownloadItem::TARGET_DISPOSITION_PROMPT, 1772 1773 EXPECT_CRDOWNLOAD 1774 }, 1775 FILE_PATH_LITERAL("foo.txt.crdownload"), 1776 FILE_PATH_LITERAL("some_path/bar.txt.crdownload") 1777 }, 1778 1779 { 1780 { 1781 // 2: Automatic Dangerous 1782 AUTOMATIC, 1783 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE, 1784 "http://example.com/foo.html", "", 1785 FILE_PATH_LITERAL(""), 1786 1787 FILE_PATH_LITERAL(""), 1788 FILE_PATH_LITERAL("foo.html"), 1789 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 1790 1791 EXPECT_UNCONFIRMED 1792 }, 1793 FILE_PATH_LITERAL("Unconfirmed abcd.crdownload"), 1794 FILE_PATH_LITERAL("Unconfirmed abcd.crdownload") 1795 }, 1796 1797 { 1798 { 1799 // 3: Automatic Dangerous 1800 AUTOMATIC, 1801 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE, 1802 "http://example.com/foo.html", "", 1803 FILE_PATH_LITERAL(""), 1804 1805 FILE_PATH_LITERAL(""), 1806 FILE_PATH_LITERAL("foo.html"), 1807 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 1808 1809 EXPECT_UNCONFIRMED 1810 }, 1811 FILE_PATH_LITERAL("other_path/Unconfirmed abcd.crdownload"), 1812 // Rely on the EXPECT_UNCONFIRMED check in the general test settings. A 1813 // new intermediate path of the form "Unconfirmed <number>.crdownload" 1814 // should be generated for this case since the initial intermediate path 1815 // is in the wrong directory. 1816 FILE_PATH_LITERAL("") 1817 }, 1818 1819 { 1820 { 1821 // 3: Forced Safe: Initial path is ignored due to the forced path. 1822 FORCED, 1823 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 1824 "http://example.com/foo.txt", "", 1825 FILE_PATH_LITERAL("forced-foo.txt"), 1826 1827 FILE_PATH_LITERAL(""), 1828 FILE_PATH_LITERAL("forced-foo.txt"), 1829 DownloadItem::TARGET_DISPOSITION_OVERWRITE, 1830 1831 EXPECT_LOCAL_PATH 1832 }, 1833 FILE_PATH_LITERAL("forced-foo.txt"), 1834 FILE_PATH_LITERAL("forced-foo.txt") 1835 }, 1836 }; 1837 1838 // The test assumes that .html files have a danger level of 1839 // ALLOW_ON_USER_GESTURE. 1840 ASSERT_EQ(download_util::ALLOW_ON_USER_GESTURE, 1841 download_util::GetFileDangerLevel( 1842 base::FilePath(FILE_PATH_LITERAL("foo.html")))); 1843 1844 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kIntermediateNameTestCases); ++i) { 1845 SCOPED_TRACE(testing::Message() << "Running test case " << i); 1846 const IntermediateNameTestCase& test_case = kIntermediateNameTestCases[i]; 1847 scoped_ptr<content::MockDownloadItem> item( 1848 CreateActiveDownloadItem(i, test_case.general)); 1849 1850 ON_CALL(*item.get(), GetLastReason()) 1851 .WillByDefault(Return( 1852 content::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED)); 1853 ON_CALL(*item.get(), GetFullPath()) 1854 .WillByDefault(ReturnRefOfCopy( 1855 GetPathInDownloadDir(test_case.initial_intermediate_path))); 1856 ON_CALL(*item.get(), GetDangerType()) 1857 .WillByDefault(Return(test_case.general.expected_danger_type)); 1858 1859 base::WeakPtrFactory<DownloadTargetDeterminerTest> factory(this); 1860 base::RunLoop run_loop; 1861 content::DownloadTargetCallback verifier_callback = 1862 base::Bind(&DownloadTargetDeterminerTest::DownloadTargetVerifier, 1863 factory.GetWeakPtr(), 1864 run_loop.QuitClosure(), 1865 test_case.general); 1866 content::DownloadTargetCallback test_callback = 1867 base::Bind(&IntermediatePathVerifier, 1868 GetPathInDownloadDir(test_case.expected_intermediate_path), 1869 verifier_callback); 1870 DownloadTargetDeterminer::Start(item.get(), 1871 GetPathInDownloadDir(kInitialPath), 1872 download_prefs(), 1873 delegate(), 1874 test_callback); 1875 run_loop.Run(); 1876 ::testing::Mock::VerifyAndClearExpectations(delegate()); 1877 } 1878 } 1879 1880 } // namespace 1881