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