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.
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/history/history_service.h"
19 #include "chrome/browser/history/history_service_factory.h"
20 #include "chrome/browser/history/history_types.h"
21 #include "chrome/common/extensions/extension.h"
22 #include "chrome/common/pref_names.h"
23 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
24 #include "chrome/test/base/testing_pref_service_syncable.h"
25 #include "chrome/test/base/testing_profile.h"
26 #include "content/public/browser/download_interrupt_reasons.h"
27 #include "content/public/browser/web_contents.h"
28 #include "content/public/browser/web_contents_delegate.h"
29 #include "content/public/test/mock_download_item.h"
30 #include "content/public/test/test_browser_thread.h"
31 #include "content/public/test/test_renderer_host.h"
32 #include "content/public/test/web_contents_tester.h"
33 #include "testing/gmock/include/gmock/gmock.h"
34 #include "testing/gtest/include/gtest/gtest.h"
36 using ::testing::AnyNumber;
37 using ::testing::Invoke;
39 using ::testing::Return;
40 using ::testing::ReturnRef;
41 using ::testing::ReturnRefOfCopy;
42 using ::testing::Truly;
43 using ::testing::WithArg;
45 using content::DownloadItem;
50 class NullWebContentsDelegate : public content::WebContentsDelegate {
52 NullWebContentsDelegate() {}
53 virtual ~NullWebContentsDelegate() {}
56 // Google Mock action that posts a task to the current message loop that invokes
57 // the first argument of the mocked method as a callback. Said argument must be
58 // a base::Callback<void(ParamType)>. |result| must be of |ParamType| and is
59 // bound as that parameter.
63 // virtual void Foo(base::Callback<void(bool)> callback);
66 // EXPECT_CALL(mock_fooclass_instance, Foo(callback))
67 // .WillOnce(ScheduleCallback(false));
68 ACTION_P(ScheduleCallback, result0) {
69 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(arg0, result0));
72 // Similar to ScheduleCallback, but binds 2 arguments.
73 ACTION_P2(ScheduleCallback2, result0, result1) {
74 base::MessageLoop::current()->PostTask(
75 FROM_HERE, base::Bind(arg0, result0, result1));
78 // Used with DownloadTestCase. Indicates the type of test case. The expectations
79 // for the test is set based on the type.
83 FORCED // Requires that forced_file_path be non-empty.
86 // Used with DownloadTestCase. Type of intermediate filename to expect.
87 enum TestCaseExpectIntermediate {
88 EXPECT_CRDOWNLOAD, // Expect path/to/target.crdownload.
89 EXPECT_UNCONFIRMED, // Expect path/to/Unconfirmed xxx.crdownload.
90 EXPECT_LOCAL_PATH, // Expect target path.
93 // Typical download test case. Used with
94 // DownloadTargetDeterminerTest::RunTestCase().
95 struct DownloadTestCase {
97 TestCaseType test_type;
99 // Expected danger type. Verified at the end of target determination.
100 content::DownloadDangerType expected_danger_type;
102 // Value of DownloadItem::GetURL()
105 // Value of DownloadItem::GetMimeType()
106 const char* mime_type;
108 // Should be non-empty if |test_type| == FORCED. Value of GetForcedFilePath().
109 const base::FilePath::CharType* forced_file_path;
111 // Expected virtual path. Specified relative to the virtual download path. If
112 // empty, assumed to be the same as |expected_local_path|.
113 const base::FilePath::CharType* expected_virtual_path;
115 // Expected local path. Specified relative to the test download path.
116 const base::FilePath::CharType* expected_local_path;
118 // Expected target disposition. If this is TARGET_DISPOSITION_PROMPT, then the
119 // test run will expect ChromeDownloadManagerDelegate to prompt the user for a
120 // download location.
121 DownloadItem::TargetDisposition expected_disposition;
123 // Type of intermediate path to expect.
124 TestCaseExpectIntermediate expected_intermediate;
127 class MockDownloadTargetDeterminerDelegate
128 : public DownloadTargetDeterminerDelegate {
130 MOCK_METHOD3(CheckDownloadUrl,
131 void(content::DownloadItem*, const base::FilePath&,
132 const CheckDownloadUrlCallback&));
133 MOCK_METHOD3(NotifyExtensions,
134 void(content::DownloadItem*, const base::FilePath&,
135 const NotifyExtensionsCallback&));
136 MOCK_METHOD3(PromptUserForDownloadPath,
137 void(content::DownloadItem*, const base::FilePath&,
138 const FileSelectedCallback&));
139 MOCK_METHOD3(DetermineLocalPath,
140 void(DownloadItem*, const base::FilePath&,
141 const LocalPathCallback&));
142 MOCK_METHOD5(ReserveVirtualPath,
143 void(DownloadItem*, const base::FilePath&, bool,
144 DownloadPathReservationTracker::FilenameConflictAction,
145 const ReservedPathCallback&));
147 void SetupDefaults() {
148 ON_CALL(*this, CheckDownloadUrl(_, _, _))
149 .WillByDefault(WithArg<2>(
150 ScheduleCallback(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS)));
151 ON_CALL(*this, NotifyExtensions(_, _, _))
152 .WillByDefault(WithArg<2>(
153 ScheduleCallback2(base::FilePath(),
154 DownloadPathReservationTracker::UNIQUIFY)));
155 ON_CALL(*this, ReserveVirtualPath(_, _, _, _, _))
156 .WillByDefault(Invoke(
157 &MockDownloadTargetDeterminerDelegate::NullReserveVirtualPath));
158 ON_CALL(*this, PromptUserForDownloadPath(_, _, _))
159 .WillByDefault(Invoke(
160 &MockDownloadTargetDeterminerDelegate::NullPromptUser));
161 ON_CALL(*this, DetermineLocalPath(_, _, _))
162 .WillByDefault(Invoke(
163 &MockDownloadTargetDeterminerDelegate::NullDetermineLocalPath));
166 static void NullReserveVirtualPath(
167 DownloadItem* download,
168 const base::FilePath& virtual_path,
169 bool create_directory,
170 DownloadPathReservationTracker::FilenameConflictAction conflict_action,
171 const DownloadTargetDeterminerDelegate::ReservedPathCallback& callback);
172 static void NullPromptUser(
173 DownloadItem* download, const base::FilePath& suggested_path,
174 const FileSelectedCallback& callback);
175 static void NullDetermineLocalPath(
176 DownloadItem* download, const base::FilePath& virtual_path,
177 const LocalPathCallback& callback);
180 class DownloadTargetDeterminerTest : public ChromeRenderViewHostTestHarness {
183 virtual void SetUp() OVERRIDE;
184 virtual void TearDown() OVERRIDE;
186 // Creates MockDownloadItem and sets up default expectations.
187 content::MockDownloadItem* CreateActiveDownloadItem(
189 const DownloadTestCase& test_case);
191 // Sets the AutoOpenBasedOnExtension user preference for |path|.
192 void EnableAutoOpenBasedOnExtension(const base::FilePath& path);
194 // Set the kDownloadDefaultDirectory managed preference to |path|.
195 void SetManagedDownloadPath(const base::FilePath& path);
197 // Set the kPromptForDownload user preference to |prompt|.
198 void SetPromptForDownload(bool prompt);
200 // Given the relative path |path|, returns the full path under the temporary
201 // downloads directory.
202 base::FilePath GetPathInDownloadDir(const base::FilePath::StringType& path);
204 // Run |test_case| using |item|.
205 void RunTestCase(const DownloadTestCase& test_case,
206 const base::FilePath& initial_virtual_path,
207 content::MockDownloadItem* item);
209 // Run through |test_case_count| tests in |test_cases|. A new MockDownloadItem
210 // will be created for each test case and destroyed when the test case is
212 void RunTestCasesWithActiveItem(const DownloadTestCase test_cases[],
213 size_t test_case_count);
215 // Verifies that |target_path|, |disposition|, |expected_danger_type| and
216 // |intermediate_path| matches the expectations of |test_case|. Posts
217 // |closure| to the current message loop when done.
218 void DownloadTargetVerifier(const base::Closure& closure,
219 const DownloadTestCase& test_case,
220 const base::FilePath& local_path,
221 DownloadItem::TargetDisposition disposition,
222 content::DownloadDangerType danger_type,
223 const base::FilePath& intermediate_path);
225 const base::FilePath& test_download_dir() const {
226 return test_download_dir_.path();
229 const base::FilePath& test_virtual_dir() const {
230 return test_virtual_dir_;
233 MockDownloadTargetDeterminerDelegate* delegate() {
237 DownloadPrefs* download_prefs() {
238 return download_prefs_.get();
242 scoped_ptr<DownloadPrefs> download_prefs_;
243 ::testing::NiceMock<MockDownloadTargetDeterminerDelegate> delegate_;
244 NullWebContentsDelegate web_contents_delegate_;
245 base::ScopedTempDir test_download_dir_;
246 base::FilePath test_virtual_dir_;
249 void DownloadTargetDeterminerTest::SetUp() {
250 ChromeRenderViewHostTestHarness::SetUp();
252 download_prefs_.reset(new DownloadPrefs(profile()));
253 web_contents()->SetDelegate(&web_contents_delegate_);
254 ASSERT_TRUE(test_download_dir_.CreateUniqueTempDir());
255 test_virtual_dir_ = test_download_dir().Append(FILE_PATH_LITERAL("virtual"));
256 download_prefs_->SetDownloadPath(test_download_dir());
257 delegate_.SetupDefaults();
260 void DownloadTargetDeterminerTest::TearDown() {
261 download_prefs_.reset();
262 ChromeRenderViewHostTestHarness::TearDown();
265 content::MockDownloadItem*
266 DownloadTargetDeterminerTest::CreateActiveDownloadItem(
268 const DownloadTestCase& test_case) {
269 content::MockDownloadItem* item =
270 new ::testing::NiceMock<content::MockDownloadItem>();
271 GURL download_url(test_case.url);
272 std::vector<GURL> url_chain;
273 url_chain.push_back(download_url);
274 base::FilePath forced_file_path =
275 GetPathInDownloadDir(test_case.forced_file_path);
276 DownloadItem::TargetDisposition initial_disposition =
277 (test_case.test_type == SAVE_AS) ?
278 DownloadItem::TARGET_DISPOSITION_PROMPT :
279 DownloadItem::TARGET_DISPOSITION_OVERWRITE;
280 EXPECT_EQ(test_case.test_type == FORCED,
281 !forced_file_path.empty());
283 ON_CALL(*item, GetBrowserContext())
284 .WillByDefault(Return(profile()));
285 ON_CALL(*item, GetDangerType())
286 .WillByDefault(Return(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS));
287 ON_CALL(*item, GetForcedFilePath())
288 .WillByDefault(ReturnRefOfCopy(forced_file_path));
289 ON_CALL(*item, GetFullPath())
290 .WillByDefault(ReturnRefOfCopy(base::FilePath()));
291 ON_CALL(*item, GetHash())
292 .WillByDefault(ReturnRefOfCopy(std::string()));
293 ON_CALL(*item, GetId())
294 .WillByDefault(Return(id));
295 ON_CALL(*item, GetLastReason())
296 .WillByDefault(Return(content::DOWNLOAD_INTERRUPT_REASON_NONE));
297 ON_CALL(*item, GetMimeType())
298 .WillByDefault(Return(test_case.mime_type));
299 ON_CALL(*item, GetReferrerUrl())
300 .WillByDefault(ReturnRefOfCopy(download_url));
301 ON_CALL(*item, GetState())
302 .WillByDefault(Return(DownloadItem::IN_PROGRESS));
303 ON_CALL(*item, GetTargetDisposition())
304 .WillByDefault(Return(initial_disposition));
305 ON_CALL(*item, GetTargetFilePath())
306 .WillByDefault(ReturnRefOfCopy(base::FilePath()));
307 ON_CALL(*item, GetTransitionType())
308 .WillByDefault(Return(content::PAGE_TRANSITION_LINK));
309 ON_CALL(*item, GetURL())
310 .WillByDefault(ReturnRefOfCopy(download_url));
311 ON_CALL(*item, GetUrlChain())
312 .WillByDefault(ReturnRefOfCopy(url_chain));
313 ON_CALL(*item, GetWebContents())
314 .WillByDefault(Return(web_contents()));
315 ON_CALL(*item, HasUserGesture())
316 .WillByDefault(Return(true));
317 ON_CALL(*item, IsDangerous())
318 .WillByDefault(Return(false));
319 ON_CALL(*item, IsTemporary())
320 .WillByDefault(Return(false));
324 void DownloadTargetDeterminerTest::EnableAutoOpenBasedOnExtension(
325 const base::FilePath& path) {
326 EXPECT_TRUE(download_prefs_->EnableAutoOpenBasedOnExtension(path));
329 void DownloadTargetDeterminerTest::SetManagedDownloadPath(
330 const base::FilePath& path) {
331 profile()->GetTestingPrefService()->
332 SetManagedPref(prefs::kDownloadDefaultDirectory,
333 base::CreateFilePathValue(path));
336 void DownloadTargetDeterminerTest::SetPromptForDownload(bool prompt) {
337 profile()->GetTestingPrefService()->
338 SetBoolean(prefs::kPromptForDownload, prompt);
341 base::FilePath DownloadTargetDeterminerTest::GetPathInDownloadDir(
342 const base::FilePath::StringType& relative_path) {
343 if (relative_path.empty())
344 return base::FilePath();
345 base::FilePath full_path(test_download_dir().Append(relative_path));
346 return full_path.NormalizePathSeparators();
349 void DownloadTargetDeterminerTest::RunTestCase(
350 const DownloadTestCase& test_case,
351 const base::FilePath& initial_virtual_path,
352 content::MockDownloadItem* item) {
353 // Kick off the test.
354 base::WeakPtrFactory<DownloadTargetDeterminerTest> factory(this);
355 base::RunLoop run_loop;
356 DownloadTargetDeterminer::Start(
357 item, initial_virtual_path, download_prefs_.get(), delegate(),
358 base::Bind(&DownloadTargetDeterminerTest::DownloadTargetVerifier,
359 factory.GetWeakPtr(), run_loop.QuitClosure(), test_case));
361 ::testing::Mock::VerifyAndClearExpectations(delegate());
364 void DownloadTargetDeterminerTest::RunTestCasesWithActiveItem(
365 const DownloadTestCase test_cases[],
366 size_t test_case_count) {
367 for (size_t i = 0; i < test_case_count; ++i) {
368 scoped_ptr<content::MockDownloadItem> item(
369 CreateActiveDownloadItem(i, test_cases[i]));
370 SCOPED_TRACE(testing::Message() << "Running test case " << i);
371 RunTestCase(test_cases[i], base::FilePath(), item.get());
375 void DownloadTargetDeterminerTest::DownloadTargetVerifier(
376 const base::Closure& closure,
377 const DownloadTestCase& test_case,
378 const base::FilePath& local_path,
379 DownloadItem::TargetDisposition disposition,
380 content::DownloadDangerType danger_type,
381 const base::FilePath& intermediate_path) {
382 base::FilePath expected_local_path(
383 GetPathInDownloadDir(test_case.expected_local_path));
384 EXPECT_EQ(expected_local_path.value(), local_path.value());
385 EXPECT_EQ(test_case.expected_disposition, disposition);
386 EXPECT_EQ(test_case.expected_danger_type, danger_type);
388 switch (test_case.expected_intermediate) {
389 case EXPECT_CRDOWNLOAD:
390 EXPECT_EQ(DownloadTargetDeterminer::GetCrDownloadPath(local_path).value(),
391 intermediate_path.value());
394 case EXPECT_UNCONFIRMED:
395 // The paths (in English) look like: /path/Unconfirmed xxx.crdownload.
396 // Of this, we only check that the path is:
397 // 1. Not "/path/target.crdownload",
398 // 2. Points to the same directory as the target.
399 // 3. Has extension ".crdownload".
400 // 4. Basename starts with "Unconfirmed ".
401 EXPECT_NE(DownloadTargetDeterminer::GetCrDownloadPath(expected_local_path)
403 intermediate_path.value());
404 EXPECT_EQ(expected_local_path.DirName().value(),
405 intermediate_path.DirName().value());
406 EXPECT_TRUE(intermediate_path.MatchesExtension(
407 FILE_PATH_LITERAL(".crdownload")));
408 EXPECT_EQ(0u, intermediate_path.BaseName().value().find(
409 FILE_PATH_LITERAL("Unconfirmed ")));
412 case EXPECT_LOCAL_PATH:
413 EXPECT_EQ(expected_local_path.value(), intermediate_path.value());
416 base::MessageLoop::current()->PostTask(FROM_HERE, closure);
420 void MockDownloadTargetDeterminerDelegate::NullReserveVirtualPath(
421 DownloadItem* download,
422 const base::FilePath& virtual_path,
423 bool create_directory,
424 DownloadPathReservationTracker::FilenameConflictAction conflict_action,
425 const DownloadTargetDeterminerDelegate::ReservedPathCallback& callback) {
426 callback.Run(virtual_path, true);
430 void MockDownloadTargetDeterminerDelegate::NullPromptUser(
431 DownloadItem* download, const base::FilePath& suggested_path,
432 const FileSelectedCallback& callback) {
433 callback.Run(suggested_path);
437 void MockDownloadTargetDeterminerDelegate::NullDetermineLocalPath(
438 DownloadItem* download, const base::FilePath& virtual_path,
439 const LocalPathCallback& callback) {
440 callback.Run(virtual_path);
443 // NotifyExtensions implementation that overrides the path so that the target
444 // file is in a subdirectory called 'overridden'. If the extension is '.remove',
445 // the extension is removed.
446 void NotifyExtensionsOverridePath(
447 content::DownloadItem* download,
448 const base::FilePath& path,
449 const DownloadTargetDeterminerDelegate::NotifyExtensionsCallback&
451 base::FilePath new_path =
453 .AppendASCII("overridden")
454 .Append(path.BaseName());
455 if (new_path.MatchesExtension(FILE_PATH_LITERAL(".remove")))
456 new_path = new_path.RemoveExtension();
457 callback.Run(new_path, DownloadPathReservationTracker::UNIQUIFY);
460 void CheckDownloadUrlCheckExes(
461 content::DownloadItem* download,
462 const base::FilePath& path,
463 const DownloadTargetDeterminerDelegate::CheckDownloadUrlCallback&
465 if (path.MatchesExtension(FILE_PATH_LITERAL(".exe")))
466 callback.Run(content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT);
468 callback.Run(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
471 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_Basic) {
472 const DownloadTestCase kBasicTestCases[] = {
476 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
477 "http://example.com/foo.txt", "text/plain",
478 FILE_PATH_LITERAL(""),
480 FILE_PATH_LITERAL(""),
481 FILE_PATH_LITERAL("foo.txt"),
482 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
490 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
491 "http://example.com/foo.txt", "text/plain",
492 FILE_PATH_LITERAL(""),
494 FILE_PATH_LITERAL(""),
495 FILE_PATH_LITERAL("foo.txt"),
496 DownloadItem::TARGET_DISPOSITION_PROMPT,
502 // 2: Automatic Dangerous
504 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE,
505 "http://example.com/foo.html", "",
506 FILE_PATH_LITERAL(""),
508 FILE_PATH_LITERAL(""),
509 FILE_PATH_LITERAL("foo.html"),
510 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
518 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
519 "http://example.com/foo.txt", "",
520 FILE_PATH_LITERAL("forced-foo.txt"),
522 FILE_PATH_LITERAL(""),
523 FILE_PATH_LITERAL("forced-foo.txt"),
524 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
530 // The test assumes that .html files have a danger level of
531 // ALLOW_ON_USER_GESTURE.
532 ASSERT_EQ(download_util::ALLOW_ON_USER_GESTURE,
533 download_util::GetFileDangerLevel(
534 base::FilePath(FILE_PATH_LITERAL("foo.html"))));
535 RunTestCasesWithActiveItem(kBasicTestCases, arraysize(kBasicTestCases));
538 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_CancelSaveAs) {
539 const DownloadTestCase kCancelSaveAsTestCases[] = {
541 // 0: Save_As Safe, Cancelled.
543 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
544 "http://example.com/foo.txt", "text/plain",
545 FILE_PATH_LITERAL(""),
547 FILE_PATH_LITERAL(""),
548 FILE_PATH_LITERAL(""),
549 DownloadItem::TARGET_DISPOSITION_PROMPT,
554 ON_CALL(*delegate(), PromptUserForDownloadPath(_, _, _))
555 .WillByDefault(WithArg<2>(ScheduleCallback(base::FilePath())));
556 RunTestCasesWithActiveItem(kCancelSaveAsTestCases,
557 arraysize(kCancelSaveAsTestCases));
560 // The SafeBrowsing check is performed early. Make sure that a download item
561 // that has been marked as DANGEROUS_URL behaves correctly.
562 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_DangerousUrl) {
563 const DownloadTestCase kSafeBrowsingTestCases[] = {
565 // 0: Automatic Dangerous URL
567 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL,
568 "http://phishing.example.com/foo.txt", "",
569 FILE_PATH_LITERAL(""),
571 FILE_PATH_LITERAL(""),
572 FILE_PATH_LITERAL("foo.txt"),
573 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
579 // 1: Save As Dangerous URL
581 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL,
582 "http://phishing.example.com/foo.txt", "",
583 FILE_PATH_LITERAL(""),
585 FILE_PATH_LITERAL(""),
586 FILE_PATH_LITERAL("foo.txt"),
587 DownloadItem::TARGET_DISPOSITION_PROMPT,
593 // 2: Forced Dangerous URL
595 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL,
596 "http://phishing.example.com/foo.txt", "",
597 FILE_PATH_LITERAL("forced-foo.txt"),
599 FILE_PATH_LITERAL(""),
600 FILE_PATH_LITERAL("forced-foo.txt"),
601 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
607 // 3: Automatic Dangerous URL + Dangerous file. Dangerous URL takes
610 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL,
611 "http://phishing.example.com/foo.html", "",
612 FILE_PATH_LITERAL(""),
614 FILE_PATH_LITERAL(""),
615 FILE_PATH_LITERAL("foo.html"),
616 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
622 // 4: Save As Dangerous URL + Dangerous file
624 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL,
625 "http://phishing.example.com/foo.html", "",
626 FILE_PATH_LITERAL(""),
628 FILE_PATH_LITERAL(""),
629 FILE_PATH_LITERAL("foo.html"),
630 DownloadItem::TARGET_DISPOSITION_PROMPT,
636 // 5: Forced Dangerous URL + Dangerous file
638 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL,
639 "http://phishing.example.com/foo.html", "",
640 FILE_PATH_LITERAL("forced-foo.html"),
642 FILE_PATH_LITERAL(""),
643 FILE_PATH_LITERAL("forced-foo.html"),
644 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
650 ON_CALL(*delegate(), CheckDownloadUrl(_, _, _))
651 .WillByDefault(WithArg<2>(ScheduleCallback(
652 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL)));
653 RunTestCasesWithActiveItem(kSafeBrowsingTestCases,
654 arraysize(kSafeBrowsingTestCases));
657 // The SafeBrowsing check is performed early. Make sure that a download item
658 // that has been marked as MAYBE_DANGEROUS_CONTENT behaves correctly.
659 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_MaybeDangerousContent) {
660 const DownloadTestCase kSafeBrowsingTestCases[] = {
662 // 0: Automatic Maybe dangerous content
664 content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT,
665 "http://phishing.example.com/foo.exe", "",
666 FILE_PATH_LITERAL(""),
668 FILE_PATH_LITERAL(""),
669 FILE_PATH_LITERAL("foo.exe"),
670 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
676 // 1: Save As Maybe dangerous content
678 content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT,
679 "http://phishing.example.com/foo.exe", "",
680 FILE_PATH_LITERAL(""),
682 FILE_PATH_LITERAL(""),
683 FILE_PATH_LITERAL("foo.exe"),
684 DownloadItem::TARGET_DISPOSITION_PROMPT,
690 // 2: Forced Maybe dangerous content
692 content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT,
693 "http://phishing.example.com/foo.exe", "",
694 FILE_PATH_LITERAL("forced-foo.exe"),
696 FILE_PATH_LITERAL(""),
697 FILE_PATH_LITERAL("forced-foo.exe"),
698 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
704 ON_CALL(*delegate(), CheckDownloadUrl(_, _, _))
705 .WillByDefault(WithArg<2>(ScheduleCallback(
706 content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT)));
707 RunTestCasesWithActiveItem(kSafeBrowsingTestCases,
708 arraysize(kSafeBrowsingTestCases));
711 // Test whether the last saved directory is used for 'Save As' downloads.
712 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_LastSavePath) {
713 const DownloadTestCase kLastSavePathTestCasesPre[] = {
715 // 0: If the last save path is empty, then the default download directory
718 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
719 "http://example.com/foo.txt", "text/plain",
720 FILE_PATH_LITERAL(""),
722 FILE_PATH_LITERAL(""),
723 FILE_PATH_LITERAL("foo.txt"),
724 DownloadItem::TARGET_DISPOSITION_PROMPT,
730 // These test cases are run with a last save path set to a non-emtpy local
731 // download directory.
732 const DownloadTestCase kLastSavePathTestCasesPost[] = {
734 // 0: This test case is run with the last download directory set to
735 // '<test_download_dir()>/foo'.
737 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
738 "http://example.com/foo.txt", "text/plain",
739 FILE_PATH_LITERAL(""),
741 FILE_PATH_LITERAL(""),
742 FILE_PATH_LITERAL("foo/foo.txt"),
743 DownloadItem::TARGET_DISPOSITION_PROMPT,
749 // 1: Start an automatic download. This should be saved to the user's
750 // default download directory and not the last used Save As directory.
752 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
753 "http://example.com/foo.txt", "text/plain",
754 FILE_PATH_LITERAL(""),
756 FILE_PATH_LITERAL(""),
757 FILE_PATH_LITERAL("foo.txt"),
758 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
764 // This test case is run with the last save path set to a non-empty virtual
766 const DownloadTestCase kLastSavePathTestCasesVirtual[] = {
769 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
770 "http://example.com/foo.txt", "text/plain",
771 FILE_PATH_LITERAL(""),
773 FILE_PATH_LITERAL("virtual/foo/foo.txt"),
774 FILE_PATH_LITERAL("bar.txt"),
775 DownloadItem::TARGET_DISPOSITION_PROMPT,
782 SCOPED_TRACE(testing::Message()
783 << "Running with default download path");
784 base::FilePath prompt_path =
785 GetPathInDownloadDir(FILE_PATH_LITERAL("foo.txt"));
786 EXPECT_CALL(*delegate(), PromptUserForDownloadPath(_, prompt_path, _));
787 RunTestCasesWithActiveItem(kLastSavePathTestCasesPre,
788 arraysize(kLastSavePathTestCasesPre));
791 // Try with a non-empty last save path.
793 SCOPED_TRACE(testing::Message()
794 << "Running with local last_selected_directory");
795 download_prefs()->SetSaveFilePath(test_download_dir().AppendASCII("foo"));
796 base::FilePath prompt_path =
797 GetPathInDownloadDir(FILE_PATH_LITERAL("foo/foo.txt"));
798 EXPECT_CALL(*delegate(), PromptUserForDownloadPath(_, prompt_path, _));
799 RunTestCasesWithActiveItem(kLastSavePathTestCasesPost,
800 arraysize(kLastSavePathTestCasesPost));
803 // And again, but this time use a virtual directory.
805 SCOPED_TRACE(testing::Message()
806 << "Running with virtual last_selected_directory");
807 base::FilePath last_selected_dir = test_virtual_dir().AppendASCII("foo");
808 base::FilePath virtual_path = last_selected_dir.AppendASCII("foo.txt");
809 download_prefs()->SetSaveFilePath(last_selected_dir);
810 EXPECT_CALL(*delegate(), PromptUserForDownloadPath(
811 _, last_selected_dir.AppendASCII("foo.txt"), _));
812 EXPECT_CALL(*delegate(), DetermineLocalPath(_, virtual_path, _))
813 .WillOnce(WithArg<2>(ScheduleCallback(
814 GetPathInDownloadDir(FILE_PATH_LITERAL("bar.txt")))));
815 RunTestCasesWithActiveItem(kLastSavePathTestCasesVirtual,
816 arraysize(kLastSavePathTestCasesVirtual));
820 // These tests are run with the default downloads folder set to a virtual
822 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_DefaultVirtual) {
823 // The default download directory is the virutal path.
824 download_prefs()->SetDownloadPath(test_virtual_dir());
827 SCOPED_TRACE(testing::Message() << "Automatic Safe Download");
828 const DownloadTestCase kAutomaticDownloadToVirtualDir = {
830 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
831 "http://example.com/foo.txt", "text/plain",
832 FILE_PATH_LITERAL(""),
834 // Downloaded to default virtual directory.
835 FILE_PATH_LITERAL("virtual/foo.txt"),
836 FILE_PATH_LITERAL("foo-local.txt"),
837 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
841 EXPECT_CALL(*delegate(), DetermineLocalPath(_, _, _))
842 .WillOnce(WithArg<2>(ScheduleCallback(
843 GetPathInDownloadDir(FILE_PATH_LITERAL("foo-local.txt")))));
844 RunTestCasesWithActiveItem(&kAutomaticDownloadToVirtualDir, 1);
848 SCOPED_TRACE(testing::Message() << "Save As to virtual directory");
849 const DownloadTestCase kSaveAsToVirtualDir = {
851 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
852 "http://example.com/bar.txt", "text/plain",
853 FILE_PATH_LITERAL(""),
855 // The response to the download prompt is to choose the 'prompted.txt'
857 FILE_PATH_LITERAL("virtual/prompted.txt"),
858 FILE_PATH_LITERAL("foo-local.txt"),
859 DownloadItem::TARGET_DISPOSITION_PROMPT,
863 EXPECT_CALL(*delegate(), DetermineLocalPath(_, _, _))
864 .WillOnce(WithArg<2>(ScheduleCallback(
865 GetPathInDownloadDir(FILE_PATH_LITERAL("foo-local.txt")))));
866 EXPECT_CALL(*delegate(), PromptUserForDownloadPath(
867 _, test_virtual_dir().AppendASCII("bar.txt"), _))
868 .WillOnce(WithArg<2>(ScheduleCallback(
869 test_virtual_dir().AppendASCII("prompted.txt"))));
870 RunTestCasesWithActiveItem(&kSaveAsToVirtualDir, 1);
874 SCOPED_TRACE(testing::Message() << "Save As to local directory");
875 const DownloadTestCase kSaveAsToLocalDir = {
877 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
878 "http://example.com/bar.txt", "text/plain",
879 FILE_PATH_LITERAL(""),
881 // Response to the 'Save As' is to choose the local path for 'foo-x.txt'.
882 FILE_PATH_LITERAL(""),
883 FILE_PATH_LITERAL("foo-x.txt"),
884 DownloadItem::TARGET_DISPOSITION_PROMPT,
888 EXPECT_CALL(*delegate(), PromptUserForDownloadPath(
889 _, test_virtual_dir().AppendASCII("bar.txt"), _))
890 .WillOnce(WithArg<2>(ScheduleCallback(
891 GetPathInDownloadDir(FILE_PATH_LITERAL("foo-x.txt")))));
892 RunTestCasesWithActiveItem(&kSaveAsToLocalDir, 1);
896 SCOPED_TRACE(testing::Message() << "Forced safe download");
897 const DownloadTestCase kForcedSafe = {
899 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
900 "http://example.com/foo.txt", "",
901 FILE_PATH_LITERAL("forced-foo.txt"),
903 // Forced paths should be left as-is.
904 FILE_PATH_LITERAL(""),
905 FILE_PATH_LITERAL("forced-foo.txt"),
906 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
910 RunTestCasesWithActiveItem(&kForcedSafe, 1);
914 // Test that an inactive download will still get a virtual or local download
916 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_InactiveDownload) {
917 const DownloadTestCase kInactiveTestCases[] = {
920 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
921 "http://example.com/foo.txt", "text/plain",
922 FILE_PATH_LITERAL(""),
924 FILE_PATH_LITERAL("foo.txt"),
925 FILE_PATH_LITERAL(""),
926 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
933 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
934 "http://example.com/foo.txt", "text/plain",
935 FILE_PATH_LITERAL(""),
937 FILE_PATH_LITERAL("foo.txt"),
938 FILE_PATH_LITERAL(""),
939 DownloadItem::TARGET_DISPOSITION_PROMPT,
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(_, _, _))
956 RunTestCase(test_case, base::FilePath(), item.get());
960 // If the reserved path could not be verified, then the user should see a
962 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_ReservationFailed) {
963 const DownloadTestCase kReservationFailedCases[] = {
965 // 0: Automatic download. Since the reservation fails, the disposition of
966 // the target is to prompt, but the returned path is used.
968 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
969 "http://example.com/foo.txt", "text/plain",
970 FILE_PATH_LITERAL(""),
972 FILE_PATH_LITERAL(""),
973 FILE_PATH_LITERAL("bar.txt"),
974 DownloadItem::TARGET_DISPOSITION_PROMPT,
980 // Setup ReserveVirtualPath() to fail.
981 ON_CALL(*delegate(), ReserveVirtualPath(_, _, _, _, _))
982 .WillByDefault(WithArg<4>(ScheduleCallback2(
983 GetPathInDownloadDir(FILE_PATH_LITERAL("bar.txt")), false)));
984 RunTestCasesWithActiveItem(kReservationFailedCases,
985 arraysize(kReservationFailedCases));
988 // If the local path could not be determined, the download should be cancelled.
989 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_LocalPathFailed) {
990 const DownloadTestCase kLocalPathFailedCases[] = {
992 // 0: Automatic download.
994 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
995 "http://example.com/foo.txt", "text/plain",
996 FILE_PATH_LITERAL(""),
998 FILE_PATH_LITERAL(""),
999 FILE_PATH_LITERAL(""),
1000 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1006 base::FilePath expected_virtual_path(
1007 GetPathInDownloadDir(FILE_PATH_LITERAL("virtual/foo.txt")));
1008 // The default download directory is the virtual path.
1009 download_prefs()->SetDownloadPath(test_virtual_dir());
1010 // Simulate failed call to DetermineLocalPath.
1011 EXPECT_CALL(*delegate(), DetermineLocalPath(
1012 _, GetPathInDownloadDir(FILE_PATH_LITERAL("virtual/foo.txt")), _))
1013 .WillOnce(WithArg<2>(ScheduleCallback(base::FilePath())));
1014 RunTestCasesWithActiveItem(kLocalPathFailedCases,
1015 arraysize(kLocalPathFailedCases));
1018 // Downloads that have a danger level of ALLOW_ON_USER_GESTURE should be marked
1019 // as safe depending on whether there was a user gesture associated with the
1020 // download and whether the referrer was visited prior to today.
1021 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_VisitedReferrer) {
1022 const DownloadTestCase kVisitedReferrerCases[] = {
1023 // http://visited.example.com/ is added to the history as a visit that
1024 // happened prior to today.
1026 // 0: Safe download due to visiting referrer before.
1028 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1029 "http://visited.example.com/foo.html", "text/html",
1030 FILE_PATH_LITERAL(""),
1032 FILE_PATH_LITERAL(""),
1033 FILE_PATH_LITERAL("foo.html"),
1034 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1040 // 1: Dangerous due to not having visited referrer before.
1042 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE,
1043 "http://not-visited.example.com/foo.html", "text/html",
1044 FILE_PATH_LITERAL(""),
1046 FILE_PATH_LITERAL(""),
1047 FILE_PATH_LITERAL("foo.html"),
1048 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1054 // 2: Safe because the user is being prompted.
1056 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1057 "http://not-visited.example.com/foo.html", "text/html",
1058 FILE_PATH_LITERAL(""),
1060 FILE_PATH_LITERAL(""),
1061 FILE_PATH_LITERAL("foo.html"),
1062 DownloadItem::TARGET_DISPOSITION_PROMPT,
1068 // 3: Safe because of forced path.
1070 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1071 "http://not-visited.example.com/foo.html", "text/html",
1072 FILE_PATH_LITERAL("foo.html"),
1074 FILE_PATH_LITERAL(""),
1075 FILE_PATH_LITERAL("foo.html"),
1076 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1082 // This test assumes that the danger level of .html files is
1083 // ALLOW_ON_USER_GESTURE.
1084 ASSERT_EQ(download_util::ALLOW_ON_USER_GESTURE,
1085 download_util::GetFileDangerLevel(
1086 base::FilePath(FILE_PATH_LITERAL("foo.html"))));
1088 // First the history service must exist.
1089 ASSERT_TRUE(profile()->CreateHistoryService(false, false));
1091 GURL url("http://visited.example.com/visited-link.html");
1092 // The time of visit is picked to be several seconds prior to the most recent
1094 base::Time time_of_visit(
1095 base::Time::Now().LocalMidnight() - base::TimeDelta::FromSeconds(10));
1096 HistoryService* history_service =
1097 HistoryServiceFactory::GetForProfile(profile(), Profile::EXPLICIT_ACCESS);
1098 ASSERT_TRUE(history_service);
1099 history_service->AddPage(url, time_of_visit, history::SOURCE_BROWSED);
1101 RunTestCasesWithActiveItem(kVisitedReferrerCases,
1102 arraysize(kVisitedReferrerCases));
1105 // These test cases are run with "Prompt for download" user preference set to
1107 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_PromptAlways) {
1108 const DownloadTestCase kPromptingTestCases[] = {
1110 // 0: Safe Automatic - Should prompt because of "Prompt for download"
1111 // preference setting.
1113 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1114 "http://example.com/foo.txt", "text/plain",
1115 FILE_PATH_LITERAL(""),
1117 FILE_PATH_LITERAL(""),
1118 FILE_PATH_LITERAL("foo.txt"),
1119 DownloadItem::TARGET_DISPOSITION_PROMPT,
1125 // 1: Safe Forced - Shouldn't prompt.
1127 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1128 "http://example.com/foo.txt", "text/plain",
1129 FILE_PATH_LITERAL("foo.txt"),
1131 FILE_PATH_LITERAL(""),
1132 FILE_PATH_LITERAL("foo.txt"),
1133 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1139 // 2: Automatic - The filename extension is marked as one that we will
1140 // open automatically. Shouldn't prompt.
1142 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1143 "http://example.com/foo.dummy", "",
1144 FILE_PATH_LITERAL(""),
1146 FILE_PATH_LITERAL(""),
1147 FILE_PATH_LITERAL("foo.dummy"),
1148 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1154 SetPromptForDownload(true);
1155 EnableAutoOpenBasedOnExtension(
1156 base::FilePath(FILE_PATH_LITERAL("dummy.dummy")));
1157 RunTestCasesWithActiveItem(kPromptingTestCases,
1158 arraysize(kPromptingTestCases));
1161 #if !defined(OS_ANDROID)
1162 // These test cases are run with "Prompt for download" user preference set to
1163 // true. Automatic extension downloads shouldn't cause prompting.
1164 // Android doesn't support extensions.
1165 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_PromptAlways_Extension) {
1166 const DownloadTestCase kPromptingTestCases[] = {
1168 // 0: Automatic Browser Extension download. - Shouldn't prompt for browser
1169 // extension downloads even if "Prompt for download" preference is set.
1171 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE,
1172 "http://example.com/foo.crx",
1173 extensions::Extension::kMimeType,
1174 FILE_PATH_LITERAL(""),
1176 FILE_PATH_LITERAL(""),
1177 FILE_PATH_LITERAL("foo.crx"),
1178 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1185 // 1: Automatic User Script - Shouldn't prompt for user script downloads
1186 // even if "Prompt for download" preference is set. ".js" files are
1187 // considered dangerous on Windows.
1189 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE,
1190 "http://example.com/foo.user.js", "",
1191 FILE_PATH_LITERAL(""),
1193 FILE_PATH_LITERAL(""),
1194 FILE_PATH_LITERAL("foo.user.js"),
1195 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1201 // 1: Automatic User Script - Shouldn't prompt for user script downloads
1202 // even if "Prompt for download" preference is set.
1204 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1205 "http://example.com/foo.user.js", "",
1206 FILE_PATH_LITERAL(""),
1208 FILE_PATH_LITERAL(""),
1209 FILE_PATH_LITERAL("foo.user.js"),
1210 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1217 SetPromptForDownload(true);
1218 RunTestCasesWithActiveItem(kPromptingTestCases,
1219 arraysize(kPromptingTestCases));
1223 // If the download path is managed, then we don't show any prompts.
1224 // Note that if the download path is managed, then PromptForDownload() is false.
1225 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_ManagedPath) {
1226 const DownloadTestCase kManagedPathTestCases[] = {
1228 // 0: Automatic Safe
1230 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1231 "http://example.com/foo.txt", "text/plain",
1232 FILE_PATH_LITERAL(""),
1234 FILE_PATH_LITERAL(""),
1235 FILE_PATH_LITERAL("foo.txt"),
1236 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1244 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1245 "http://example.com/foo.txt", "text/plain",
1246 FILE_PATH_LITERAL(""),
1248 FILE_PATH_LITERAL(""),
1249 FILE_PATH_LITERAL("foo.txt"),
1250 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1256 SetManagedDownloadPath(test_download_dir());
1257 ASSERT_TRUE(download_prefs()->IsDownloadPathManaged());
1258 RunTestCasesWithActiveItem(kManagedPathTestCases,
1259 arraysize(kManagedPathTestCases));
1262 // Test basic functionality supporting extensions that want to override download
1264 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_NotifyExtensionsSafe) {
1265 const DownloadTestCase kNotifyExtensionsTestCases[] = {
1267 // 0: Automatic Safe
1269 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1270 "http://example.com/foo.txt", "text/plain",
1271 FILE_PATH_LITERAL(""),
1273 FILE_PATH_LITERAL(""),
1274 FILE_PATH_LITERAL("overridden/foo.txt"),
1275 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1283 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1284 "http://example.com/foo.txt", "text/plain",
1285 FILE_PATH_LITERAL(""),
1287 FILE_PATH_LITERAL(""),
1288 FILE_PATH_LITERAL("overridden/foo.txt"),
1289 DownloadItem::TARGET_DISPOSITION_PROMPT,
1295 // 2: Automatic Dangerous
1297 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE,
1298 "http://example.com/foo.html", "",
1299 FILE_PATH_LITERAL(""),
1301 FILE_PATH_LITERAL(""),
1302 FILE_PATH_LITERAL("overridden/foo.html"),
1303 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1311 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1312 "http://example.com/foo.txt", "",
1313 FILE_PATH_LITERAL("forced-foo.txt"),
1315 FILE_PATH_LITERAL(""),
1316 FILE_PATH_LITERAL("forced-foo.txt"),
1317 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1323 ON_CALL(*delegate(), NotifyExtensions(_, _, _))
1324 .WillByDefault(Invoke(&NotifyExtensionsOverridePath));
1325 RunTestCasesWithActiveItem(kNotifyExtensionsTestCases,
1326 arraysize(kNotifyExtensionsTestCases));
1329 // Test that filenames provided by extensions are passed into SafeBrowsing
1330 // checks and dangerous download checks.
1331 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_NotifyExtensionsUnsafe) {
1332 const DownloadTestCase kNotifyExtensionsTestCases[] = {
1334 // 0: Automatic Safe : Later overridden by a dangerous filetype.
1336 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE,
1337 "http://example.com/foo.html.remove", "text/plain",
1338 FILE_PATH_LITERAL(""),
1340 FILE_PATH_LITERAL(""),
1341 FILE_PATH_LITERAL("overridden/foo.html"),
1342 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1348 // 1: Automatic Safe : Later overridden by a potentially dangerous
1351 content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT,
1352 "http://example.com/foo.exe.remove", "text/plain",
1353 FILE_PATH_LITERAL(""),
1355 FILE_PATH_LITERAL(""),
1356 FILE_PATH_LITERAL("overridden/foo.exe"),
1357 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1363 ON_CALL(*delegate(), NotifyExtensions(_, _, _))
1364 .WillByDefault(Invoke(&NotifyExtensionsOverridePath));
1365 ON_CALL(*delegate(), CheckDownloadUrl(_, _, _))
1366 .WillByDefault(Invoke(&CheckDownloadUrlCheckExes));
1367 RunTestCasesWithActiveItem(kNotifyExtensionsTestCases,
1368 arraysize(kNotifyExtensionsTestCases));
1371 // Test that conflict actions set by extensions are passed correctly into
1372 // ReserveVirtualPath.
1373 TEST_F(DownloadTargetDeterminerTest,
1374 TargetDeterminer_NotifyExtensionsConflict) {
1375 const DownloadTestCase kNotifyExtensionsTestCase = {
1377 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1378 "http://example.com/foo.txt", "text/plain",
1379 FILE_PATH_LITERAL(""),
1381 FILE_PATH_LITERAL(""),
1382 FILE_PATH_LITERAL("overridden/foo.txt"),
1383 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1388 const DownloadTestCase& test_case = kNotifyExtensionsTestCase;
1389 scoped_ptr<content::MockDownloadItem> item(
1390 CreateActiveDownloadItem(0, test_case));
1391 base::FilePath overridden_path(FILE_PATH_LITERAL("overridden/foo.txt"));
1392 base::FilePath full_overridden_path =
1393 GetPathInDownloadDir(overridden_path.value());
1395 // First case: An extension sets the conflict_action to OVERWRITE.
1396 EXPECT_CALL(*delegate(), NotifyExtensions(_, _, _))
1397 .WillOnce(WithArg<2>(
1398 ScheduleCallback2(overridden_path,
1399 DownloadPathReservationTracker::OVERWRITE)));
1400 EXPECT_CALL(*delegate(), ReserveVirtualPath(
1401 _, full_overridden_path, true, DownloadPathReservationTracker::OVERWRITE,
1402 _)).WillOnce(WithArg<4>(
1403 ScheduleCallback2(full_overridden_path, true)));
1405 RunTestCase(test_case, base::FilePath(), item.get());
1407 // Second case: An extension sets the conflict_action to PROMPT.
1408 EXPECT_CALL(*delegate(), NotifyExtensions(_, _, _))
1409 .WillOnce(WithArg<2>(
1410 ScheduleCallback2(overridden_path,
1411 DownloadPathReservationTracker::PROMPT)));
1412 EXPECT_CALL(*delegate(), ReserveVirtualPath(
1413 _, full_overridden_path, true, DownloadPathReservationTracker::PROMPT, _))
1414 .WillOnce(WithArg<4>(
1415 ScheduleCallback2(full_overridden_path, true)));
1416 RunTestCase(test_case, base::FilePath(), item.get());
1419 // Test that relative paths returned by extensions are always relative to the
1420 // default downloads path.
1421 TEST_F(DownloadTargetDeterminerTest,
1422 TargetDeterminer_NotifyExtensionsDefaultPath) {
1423 const DownloadTestCase kNotifyExtensionsTestCase = {
1425 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1426 "http://example.com/foo.txt", "text/plain",
1427 FILE_PATH_LITERAL(""),
1429 FILE_PATH_LITERAL(""),
1430 FILE_PATH_LITERAL("overridden/foo.txt"),
1431 DownloadItem::TARGET_DISPOSITION_PROMPT,
1436 const DownloadTestCase& test_case = kNotifyExtensionsTestCase;
1437 scoped_ptr<content::MockDownloadItem> item(
1438 CreateActiveDownloadItem(0, test_case));
1439 base::FilePath overridden_path(FILE_PATH_LITERAL("overridden/foo.txt"));
1440 base::FilePath full_overridden_path =
1441 GetPathInDownloadDir(overridden_path.value());
1443 download_prefs()->SetSaveFilePath(GetPathInDownloadDir(
1444 FILE_PATH_LITERAL("last_selected")));
1446 EXPECT_CALL(*delegate(), NotifyExtensions(_, _, _))
1447 .WillOnce(WithArg<2>(
1448 ScheduleCallback2(overridden_path,
1449 DownloadPathReservationTracker::UNIQUIFY)));
1450 EXPECT_CALL(*delegate(),
1451 PromptUserForDownloadPath(_, full_overridden_path, _))
1452 .WillOnce(WithArg<2>(
1453 ScheduleCallback(full_overridden_path)));
1454 RunTestCase(test_case, base::FilePath(), item.get());
1457 TEST_F(DownloadTargetDeterminerTest,
1458 TargetDeterminer_InitialVirtualPathUnsafe) {
1459 const base::FilePath::CharType* kInitialPath =
1460 FILE_PATH_LITERAL("some_path/bar.html");
1462 const DownloadTestCase kInitialPathTestCase = {
1463 // 0: Save As Save. The path generated based on the DownloadItem is safe,
1464 // but the initial path is unsafe. However, the download is not considered
1465 // dangerous since the user has been prompted.
1467 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1468 "http://example.com/foo.txt", "text/plain",
1469 FILE_PATH_LITERAL(""),
1471 FILE_PATH_LITERAL(""),
1473 DownloadItem::TARGET_DISPOSITION_PROMPT,
1478 const DownloadTestCase& test_case = kInitialPathTestCase;
1479 scoped_ptr<content::MockDownloadItem> item(
1480 CreateActiveDownloadItem(1, test_case));
1481 EXPECT_CALL(*item, GetLastReason())
1482 .WillRepeatedly(Return(
1483 content::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED));
1484 EXPECT_CALL(*item, GetTargetDisposition())
1485 .WillRepeatedly(Return(DownloadItem::TARGET_DISPOSITION_PROMPT));
1486 RunTestCase(test_case, GetPathInDownloadDir(kInitialPath), item.get());
1489 // Prompting behavior for resumed downloads is based on the last interrupt
1490 // reason. If the reason indicates that the target path may not be suitable for
1491 // the download (ACCESS_DENIED, NO_SPACE, etc..), then the user should be
1492 // prompted, and not otherwise. These test cases shouldn't result in prompting
1493 // since the error is set to NETWORK_FAILED.
1494 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_ResumedNoPrompt) {
1495 // All test cases run with GetPathInDownloadDir(kInitialPath) as the inital
1497 const base::FilePath::CharType* kInitialPath =
1498 FILE_PATH_LITERAL("some_path/bar.txt");
1500 const DownloadTestCase kResumedTestCases[] = {
1502 // 0: Automatic Safe: Initial path is ignored since the user has not been
1505 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1506 "http://example.com/foo.txt", "text/plain",
1507 FILE_PATH_LITERAL(""),
1509 FILE_PATH_LITERAL(""),
1510 FILE_PATH_LITERAL("foo.txt"),
1511 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1517 // 1: Save_As Safe: Initial path used.
1519 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1520 "http://example.com/foo.txt", "text/plain",
1521 FILE_PATH_LITERAL(""),
1523 FILE_PATH_LITERAL(""),
1525 DownloadItem::TARGET_DISPOSITION_PROMPT,
1531 // 2: Automatic Dangerous: Initial path is ignored since the user hasn't
1532 // been prompted before.
1534 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE,
1535 "http://example.com/foo.html", "",
1536 FILE_PATH_LITERAL(""),
1538 FILE_PATH_LITERAL(""),
1539 FILE_PATH_LITERAL("foo.html"),
1540 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1546 // 3: Forced Safe: Initial path is ignored due to the forced path.
1548 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1549 "http://example.com/foo.txt", "",
1550 FILE_PATH_LITERAL("forced-foo.txt"),
1552 FILE_PATH_LITERAL(""),
1553 FILE_PATH_LITERAL("forced-foo.txt"),
1554 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1560 // The test assumes that .html files have a danger level of
1561 // ALLOW_ON_USER_GESTURE.
1562 ASSERT_EQ(download_util::ALLOW_ON_USER_GESTURE,
1563 download_util::GetFileDangerLevel(
1564 base::FilePath(FILE_PATH_LITERAL("foo.html"))));
1565 for (size_t i = 0; i < arraysize(kResumedTestCases); ++i) {
1566 SCOPED_TRACE(testing::Message() << "Running test case " << i);
1567 const DownloadTestCase& test_case = kResumedTestCases[i];
1568 scoped_ptr<content::MockDownloadItem> item(
1569 CreateActiveDownloadItem(i, test_case));
1570 base::FilePath expected_path =
1571 GetPathInDownloadDir(test_case.expected_local_path);
1572 ON_CALL(*item.get(), GetLastReason())
1573 .WillByDefault(Return(
1574 content::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED));
1575 // Extensions should be notified if a new path is being generated and there
1576 // is no forced path. In the test cases above, this is true for tests with
1577 // type == AUTOMATIC.
1578 EXPECT_CALL(*delegate(), NotifyExtensions(_, _, _))
1579 .Times(test_case.test_type == AUTOMATIC ? 1 : 0);
1580 EXPECT_CALL(*delegate(), ReserveVirtualPath(_, expected_path, false, _, _));
1581 EXPECT_CALL(*delegate(), PromptUserForDownloadPath(_, expected_path, _))
1583 EXPECT_CALL(*delegate(), DetermineLocalPath(_, expected_path, _));
1584 EXPECT_CALL(*delegate(), CheckDownloadUrl(_, expected_path, _));
1585 RunTestCase(test_case, GetPathInDownloadDir(kInitialPath), item.get());
1590 // Test that a forced download doesn't prompt, even if the interrupt reason
1591 // suggests that the target path may not be suitable for downloads.
1592 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_ResumedForcedDownload) {
1593 const base::FilePath::CharType* kInitialPath =
1594 FILE_PATH_LITERAL("some_path/bar.txt");
1595 const DownloadTestCase kResumedForcedDownload = {
1598 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1599 "http://example.com/foo.txt", "",
1600 FILE_PATH_LITERAL("forced-foo.txt"),
1602 FILE_PATH_LITERAL(""),
1603 FILE_PATH_LITERAL("forced-foo.txt"),
1604 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1609 const DownloadTestCase& test_case = kResumedForcedDownload;
1610 base::FilePath expected_path =
1611 GetPathInDownloadDir(test_case.expected_local_path);
1612 scoped_ptr<content::MockDownloadItem> item(
1613 CreateActiveDownloadItem(0, test_case));
1614 ON_CALL(*item.get(), GetLastReason())
1615 .WillByDefault(Return(content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE));
1616 EXPECT_CALL(*delegate(), NotifyExtensions(_, _, _))
1617 .Times(test_case.test_type == AUTOMATIC ? 1 : 0);
1618 EXPECT_CALL(*delegate(), ReserveVirtualPath(_, expected_path, false, _, _));
1619 EXPECT_CALL(*delegate(), PromptUserForDownloadPath(_, _, _))
1621 EXPECT_CALL(*delegate(), DetermineLocalPath(_, expected_path, _));
1622 EXPECT_CALL(*delegate(), CheckDownloadUrl(_, expected_path, _));
1623 RunTestCase(test_case, GetPathInDownloadDir(kInitialPath), item.get());
1626 // Prompting behavior for resumed downloads is based on the last interrupt
1627 // reason. If the reason indicates that the target path may not be suitable for
1628 // the download (ACCESS_DENIED, NO_SPACE, etc..), then the user should be
1629 // prompted, and not otherwise. These test cases result in prompting since the
1630 // error is set to NO_SPACE.
1631 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_ResumedWithPrompt) {
1632 // All test cases run with GetPathInDownloadDir(kInitialPath) as the inital
1634 const base::FilePath::CharType* kInitialPath =
1635 FILE_PATH_LITERAL("some_path/bar.txt");
1637 const DownloadTestCase kResumedTestCases[] = {
1639 // 0: Automatic Safe
1641 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1642 "http://example.com/foo.txt", "text/plain",
1643 FILE_PATH_LITERAL(""),
1645 FILE_PATH_LITERAL(""),
1646 FILE_PATH_LITERAL("foo.txt"),
1647 DownloadItem::TARGET_DISPOSITION_PROMPT,
1655 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1656 "http://example.com/foo.txt", "text/plain",
1657 FILE_PATH_LITERAL(""),
1659 FILE_PATH_LITERAL(""),
1661 DownloadItem::TARGET_DISPOSITION_PROMPT,
1667 // 2: Automatic Dangerous
1669 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1670 "http://example.com/foo.html", "",
1671 FILE_PATH_LITERAL(""),
1673 FILE_PATH_LITERAL(""),
1674 FILE_PATH_LITERAL("foo.html"),
1675 DownloadItem::TARGET_DISPOSITION_PROMPT,
1681 // The test assumes that .html files have a danger level of
1682 // ALLOW_ON_USER_GESTURE.
1683 ASSERT_EQ(download_util::ALLOW_ON_USER_GESTURE,
1684 download_util::GetFileDangerLevel(
1685 base::FilePath(FILE_PATH_LITERAL("foo.html"))));
1686 for (size_t i = 0; i < arraysize(kResumedTestCases); ++i) {
1687 SCOPED_TRACE(testing::Message() << "Running test case " << i);
1688 download_prefs()->SetSaveFilePath(test_download_dir());
1689 const DownloadTestCase& test_case = kResumedTestCases[i];
1690 base::FilePath expected_path =
1691 GetPathInDownloadDir(test_case.expected_local_path);
1692 scoped_ptr<content::MockDownloadItem> item(
1693 CreateActiveDownloadItem(i, test_case));
1694 ON_CALL(*item.get(), GetLastReason())
1695 .WillByDefault(Return(
1696 content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE));
1697 EXPECT_CALL(*delegate(), NotifyExtensions(_, _, _))
1698 .Times(test_case.test_type == AUTOMATIC ? 1 : 0);
1699 EXPECT_CALL(*delegate(), ReserveVirtualPath(_, expected_path, false, _, _));
1700 EXPECT_CALL(*delegate(), PromptUserForDownloadPath(_, expected_path, _));
1701 EXPECT_CALL(*delegate(), DetermineLocalPath(_, expected_path, _));
1702 EXPECT_CALL(*delegate(), CheckDownloadUrl(_, expected_path, _));
1703 RunTestCase(test_case, GetPathInDownloadDir(kInitialPath), item.get());
1707 // Used with TargetDeterminer_IntermediateNameForResumed test. Verifies that
1708 // |intermediate_path| == |expected_intermediate_path| if the latter is
1710 void IntermediatePathVerifier(
1711 const base::FilePath& expected_intermediate_path,
1712 const content::DownloadTargetCallback& callback,
1713 const base::FilePath& target_path,
1714 content::DownloadItem::TargetDisposition disposition,
1715 content::DownloadDangerType danger_type,
1716 const base::FilePath& intermediate_path) {
1717 if (!expected_intermediate_path.empty())
1718 EXPECT_EQ(expected_intermediate_path, intermediate_path);
1719 callback.Run(target_path, disposition, danger_type, intermediate_path);
1722 // Test intermediate filename generation for resumed downloads.
1723 TEST_F(DownloadTargetDeterminerTest,
1724 TargetDeterminer_IntermediateNameForResumed) {
1725 // All test cases run with GetPathInDownloadDir(kInitialPath) as the inital
1727 const base::FilePath::CharType kInitialPath[] =
1728 FILE_PATH_LITERAL("some_path/bar.txt");
1730 struct IntermediateNameTestCase {
1731 // General test case settings.
1732 DownloadTestCase general;
1734 // Value of DownloadItem::GetFullPath() during test run, relative
1735 // to test download path.
1736 const base::FilePath::CharType* initial_intermediate_path;
1738 // Expected intermediate path relatvie to the test download path. An exact
1739 // match is performed if this string is non-empty. Ignored otherwise.
1740 const base::FilePath::CharType* expected_intermediate_path;
1741 } kIntermediateNameTestCases[] = {
1744 // 0: Automatic Safe
1746 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1747 "http://example.com/foo.txt", "text/plain",
1748 FILE_PATH_LITERAL(""),
1750 FILE_PATH_LITERAL(""),
1751 FILE_PATH_LITERAL("foo.txt"),
1752 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1756 FILE_PATH_LITERAL("bar.txt.crdownload"),
1757 FILE_PATH_LITERAL("foo.txt.crdownload")
1764 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1765 "http://example.com/foo.txt", "text/plain",
1766 FILE_PATH_LITERAL(""),
1768 FILE_PATH_LITERAL(""),
1770 DownloadItem::TARGET_DISPOSITION_PROMPT,
1774 FILE_PATH_LITERAL("foo.txt.crdownload"),
1775 FILE_PATH_LITERAL("some_path/bar.txt.crdownload")
1780 // 2: Automatic Dangerous
1782 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE,
1783 "http://example.com/foo.html", "",
1784 FILE_PATH_LITERAL(""),
1786 FILE_PATH_LITERAL(""),
1787 FILE_PATH_LITERAL("foo.html"),
1788 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1792 FILE_PATH_LITERAL("Unconfirmed abcd.crdownload"),
1793 FILE_PATH_LITERAL("Unconfirmed abcd.crdownload")
1798 // 3: Automatic Dangerous
1800 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE,
1801 "http://example.com/foo.html", "",
1802 FILE_PATH_LITERAL(""),
1804 FILE_PATH_LITERAL(""),
1805 FILE_PATH_LITERAL("foo.html"),
1806 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1810 FILE_PATH_LITERAL("other_path/Unconfirmed abcd.crdownload"),
1811 // Rely on the EXPECT_UNCONFIRMED check in the general test settings. A
1812 // new intermediate path of the form "Unconfirmed <number>.crdownload"
1813 // should be generated for this case since the initial intermediate path
1814 // is in the wrong directory.
1815 FILE_PATH_LITERAL("")
1820 // 3: Forced Safe: Initial path is ignored due to the forced path.
1822 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1823 "http://example.com/foo.txt", "",
1824 FILE_PATH_LITERAL("forced-foo.txt"),
1826 FILE_PATH_LITERAL(""),
1827 FILE_PATH_LITERAL("forced-foo.txt"),
1828 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1832 FILE_PATH_LITERAL("forced-foo.txt"),
1833 FILE_PATH_LITERAL("forced-foo.txt")
1837 // The test assumes that .html files have a danger level of
1838 // ALLOW_ON_USER_GESTURE.
1839 ASSERT_EQ(download_util::ALLOW_ON_USER_GESTURE,
1840 download_util::GetFileDangerLevel(
1841 base::FilePath(FILE_PATH_LITERAL("foo.html"))));
1843 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kIntermediateNameTestCases); ++i) {
1844 SCOPED_TRACE(testing::Message() << "Running test case " << i);
1845 const IntermediateNameTestCase& test_case = kIntermediateNameTestCases[i];
1846 scoped_ptr<content::MockDownloadItem> item(
1847 CreateActiveDownloadItem(i, test_case.general));
1849 ON_CALL(*item.get(), GetLastReason())
1850 .WillByDefault(Return(
1851 content::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED));
1852 ON_CALL(*item.get(), GetFullPath())
1853 .WillByDefault(ReturnRefOfCopy(
1854 GetPathInDownloadDir(test_case.initial_intermediate_path)));
1855 ON_CALL(*item.get(), GetDangerType())
1856 .WillByDefault(Return(test_case.general.expected_danger_type));
1858 base::WeakPtrFactory<DownloadTargetDeterminerTest> factory(this);
1859 base::RunLoop run_loop;
1860 content::DownloadTargetCallback verifier_callback =
1861 base::Bind(&DownloadTargetDeterminerTest::DownloadTargetVerifier,
1862 factory.GetWeakPtr(),
1863 run_loop.QuitClosure(),
1865 content::DownloadTargetCallback test_callback =
1866 base::Bind(&IntermediatePathVerifier,
1867 GetPathInDownloadDir(test_case.expected_intermediate_path),
1869 DownloadTargetDeterminer::Start(item.get(),
1870 GetPathInDownloadDir(kInitialPath),
1875 ::testing::Mock::VerifyAndClearExpectations(delegate());