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/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/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 "components/history/core/browser/history_types.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 "net/base/mime_util.h"
35 #include "testing/gmock/include/gmock/gmock.h"
36 #include "testing/gtest/include/gtest/gtest.h"
38 #if defined(ENABLE_PLUGINS)
39 #include "content/public/browser/plugin_service.h"
40 #include "content/public/browser/plugin_service_filter.h"
41 #include "content/public/common/webplugininfo.h"
44 #if defined(ENABLE_EXTENSIONS)
45 #include "extensions/common/extension.h"
48 using ::testing::AnyNumber
;
49 using ::testing::Invoke
;
51 using ::testing::Return
;
52 using ::testing::ReturnRef
;
53 using ::testing::ReturnRefOfCopy
;
54 using ::testing::Truly
;
55 using ::testing::WithArg
;
57 using content::DownloadItem
;
62 class NullWebContentsDelegate
: public content::WebContentsDelegate
{
64 NullWebContentsDelegate() {}
65 ~NullWebContentsDelegate() override
{}
68 // Google Mock action that posts a task to the current message loop that invokes
69 // the first argument of the mocked method as a callback. Said argument must be
70 // a base::Callback<void(ParamType)>. |result| must be of |ParamType| and is
71 // bound as that parameter.
75 // virtual void Foo(base::Callback<void(bool)> callback);
78 // EXPECT_CALL(mock_fooclass_instance, Foo(callback))
79 // .WillOnce(ScheduleCallback(false));
80 ACTION_P(ScheduleCallback
, result0
) {
81 base::MessageLoop::current()->PostTask(FROM_HERE
, base::Bind(arg0
, result0
));
84 // Similar to ScheduleCallback, but binds 2 arguments.
85 ACTION_P2(ScheduleCallback2
, result0
, result1
) {
86 base::MessageLoop::current()->PostTask(
87 FROM_HERE
, base::Bind(arg0
, result0
, result1
));
90 // Used with DownloadTestCase. Indicates the type of test case. The expectations
91 // for the test is set based on the type.
95 FORCED
// Requires that forced_file_path be non-empty.
98 // Used with DownloadTestCase. Type of intermediate filename to expect.
99 enum TestCaseExpectIntermediate
{
100 EXPECT_CRDOWNLOAD
, // Expect path/to/target.crdownload.
101 EXPECT_UNCONFIRMED
, // Expect path/to/Unconfirmed xxx.crdownload.
102 EXPECT_LOCAL_PATH
, // Expect target path.
105 // Typical download test case. Used with
106 // DownloadTargetDeterminerTest::RunTestCase().
107 struct DownloadTestCase
{
109 TestCaseType test_type
;
111 // Expected danger type. Verified at the end of target determination.
112 content::DownloadDangerType expected_danger_type
;
114 // Value of DownloadItem::GetURL()
117 // Value of DownloadItem::GetMimeType()
118 const char* mime_type
;
120 // Should be non-empty if |test_type| == FORCED. Value of GetForcedFilePath().
121 const base::FilePath::CharType
* forced_file_path
;
123 // Expected local path. Specified relative to the test download path.
124 const base::FilePath::CharType
* expected_local_path
;
126 // Expected target disposition. If this is TARGET_DISPOSITION_PROMPT, then the
127 // test run will expect ChromeDownloadManagerDelegate to prompt the user for a
128 // download location.
129 DownloadItem::TargetDisposition expected_disposition
;
131 // Type of intermediate path to expect.
132 TestCaseExpectIntermediate expected_intermediate
;
135 class MockDownloadTargetDeterminerDelegate
136 : public DownloadTargetDeterminerDelegate
{
138 MOCK_METHOD3(CheckDownloadUrl
,
139 void(content::DownloadItem
*, const base::FilePath
&,
140 const CheckDownloadUrlCallback
&));
141 MOCK_METHOD3(NotifyExtensions
,
142 void(content::DownloadItem
*, const base::FilePath
&,
143 const NotifyExtensionsCallback
&));
144 MOCK_METHOD3(PromptUserForDownloadPath
,
145 void(content::DownloadItem
*, const base::FilePath
&,
146 const FileSelectedCallback
&));
147 MOCK_METHOD3(DetermineLocalPath
,
148 void(DownloadItem
*, const base::FilePath
&,
149 const LocalPathCallback
&));
150 MOCK_METHOD5(ReserveVirtualPath
,
151 void(DownloadItem
*, const base::FilePath
&, bool,
152 DownloadPathReservationTracker::FilenameConflictAction
,
153 const ReservedPathCallback
&));
154 MOCK_METHOD2(GetFileMimeType
,
155 void(const base::FilePath
&,
156 const GetFileMimeTypeCallback
&));
158 void SetupDefaults() {
159 ON_CALL(*this, CheckDownloadUrl(_
, _
, _
))
160 .WillByDefault(WithArg
<2>(
161 ScheduleCallback(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
)));
162 ON_CALL(*this, NotifyExtensions(_
, _
, _
))
163 .WillByDefault(WithArg
<2>(
164 ScheduleCallback2(base::FilePath(),
165 DownloadPathReservationTracker::UNIQUIFY
)));
166 ON_CALL(*this, ReserveVirtualPath(_
, _
, _
, _
, _
))
167 .WillByDefault(Invoke(
168 &MockDownloadTargetDeterminerDelegate::NullReserveVirtualPath
));
169 ON_CALL(*this, PromptUserForDownloadPath(_
, _
, _
))
170 .WillByDefault(Invoke(
171 &MockDownloadTargetDeterminerDelegate::NullPromptUser
));
172 ON_CALL(*this, DetermineLocalPath(_
, _
, _
))
173 .WillByDefault(Invoke(
174 &MockDownloadTargetDeterminerDelegate::NullDetermineLocalPath
));
175 ON_CALL(*this, GetFileMimeType(_
, _
))
176 .WillByDefault(WithArg
<1>(
177 ScheduleCallback("")));
180 static void NullReserveVirtualPath(
181 DownloadItem
* download
,
182 const base::FilePath
& virtual_path
,
183 bool create_directory
,
184 DownloadPathReservationTracker::FilenameConflictAction conflict_action
,
185 const DownloadTargetDeterminerDelegate::ReservedPathCallback
& callback
);
186 static void NullPromptUser(
187 DownloadItem
* download
, const base::FilePath
& suggested_path
,
188 const FileSelectedCallback
& callback
);
189 static void NullDetermineLocalPath(
190 DownloadItem
* download
, const base::FilePath
& virtual_path
,
191 const LocalPathCallback
& callback
);
194 class DownloadTargetDeterminerTest
: public ChromeRenderViewHostTestHarness
{
197 virtual void SetUp() override
;
198 virtual void TearDown() override
;
200 // Creates MockDownloadItem and sets up default expectations.
201 content::MockDownloadItem
* CreateActiveDownloadItem(
203 const DownloadTestCase
& test_case
);
205 // Sets the AutoOpenBasedOnExtension user preference for |path|.
206 void EnableAutoOpenBasedOnExtension(const base::FilePath
& path
);
208 // Set the kDownloadDefaultDirectory managed preference to |path|.
209 void SetManagedDownloadPath(const base::FilePath
& path
);
211 // Set the kPromptForDownload user preference to |prompt|.
212 void SetPromptForDownload(bool prompt
);
214 // Given the relative path |path|, returns the full path under the temporary
215 // downloads directory.
216 base::FilePath
GetPathInDownloadDir(const base::FilePath::StringType
& path
);
218 // Run |test_case| using |item|.
219 void RunTestCase(const DownloadTestCase
& test_case
,
220 const base::FilePath
& initial_virtual_path
,
221 content::MockDownloadItem
* item
);
223 // Runs |test_case| with |item|. When the DownloadTargetDeterminer is done,
224 // returns the resulting DownloadTargetInfo.
225 scoped_ptr
<DownloadTargetInfo
> RunDownloadTargetDeterminer(
226 const base::FilePath
& initial_virtual_path
,
227 content::MockDownloadItem
* item
);
229 // Run through |test_case_count| tests in |test_cases|. A new MockDownloadItem
230 // will be created for each test case and destroyed when the test case is
232 void RunTestCasesWithActiveItem(const DownloadTestCase test_cases
[],
233 size_t test_case_count
);
235 // Verifies that |target_path|, |disposition|, |expected_danger_type| and
236 // |intermediate_path| matches the expectations of |test_case|. Posts
237 // |closure| to the current message loop when done.
238 void VerifyDownloadTarget(const DownloadTestCase
& test_case
,
239 const DownloadTargetInfo
* target_info
);
241 const base::FilePath
& test_download_dir() const {
242 return test_download_dir_
.path();
245 const base::FilePath
& test_virtual_dir() const {
246 return test_virtual_dir_
;
249 MockDownloadTargetDeterminerDelegate
* delegate() {
253 DownloadPrefs
* download_prefs() {
254 return download_prefs_
.get();
258 scoped_ptr
<DownloadPrefs
> download_prefs_
;
259 ::testing::NiceMock
<MockDownloadTargetDeterminerDelegate
> delegate_
;
260 NullWebContentsDelegate web_contents_delegate_
;
261 base::ScopedTempDir test_download_dir_
;
262 base::FilePath test_virtual_dir_
;
265 void DownloadTargetDeterminerTest::SetUp() {
266 ChromeRenderViewHostTestHarness::SetUp();
268 download_prefs_
.reset(new DownloadPrefs(profile()));
269 web_contents()->SetDelegate(&web_contents_delegate_
);
270 ASSERT_TRUE(test_download_dir_
.CreateUniqueTempDir());
271 test_virtual_dir_
= test_download_dir().Append(FILE_PATH_LITERAL("virtual"));
272 download_prefs_
->SetDownloadPath(test_download_dir());
273 delegate_
.SetupDefaults();
276 void DownloadTargetDeterminerTest::TearDown() {
277 download_prefs_
.reset();
278 ChromeRenderViewHostTestHarness::TearDown();
281 content::MockDownloadItem
*
282 DownloadTargetDeterminerTest::CreateActiveDownloadItem(
284 const DownloadTestCase
& test_case
) {
285 content::MockDownloadItem
* item
=
286 new ::testing::NiceMock
<content::MockDownloadItem
>();
287 GURL
download_url(test_case
.url
);
288 std::vector
<GURL
> url_chain
;
289 url_chain
.push_back(download_url
);
290 base::FilePath forced_file_path
=
291 GetPathInDownloadDir(test_case
.forced_file_path
);
292 DownloadItem::TargetDisposition initial_disposition
=
293 (test_case
.test_type
== SAVE_AS
) ?
294 DownloadItem::TARGET_DISPOSITION_PROMPT
:
295 DownloadItem::TARGET_DISPOSITION_OVERWRITE
;
296 EXPECT_EQ(test_case
.test_type
== FORCED
,
297 !forced_file_path
.empty());
299 ON_CALL(*item
, GetBrowserContext())
300 .WillByDefault(Return(profile()));
301 ON_CALL(*item
, GetDangerType())
302 .WillByDefault(Return(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
));
303 ON_CALL(*item
, GetForcedFilePath())
304 .WillByDefault(ReturnRefOfCopy(forced_file_path
));
305 ON_CALL(*item
, GetFullPath())
306 .WillByDefault(ReturnRefOfCopy(base::FilePath()));
307 ON_CALL(*item
, GetHash())
308 .WillByDefault(ReturnRefOfCopy(std::string()));
309 ON_CALL(*item
, GetId())
310 .WillByDefault(Return(id
));
311 ON_CALL(*item
, GetLastReason())
312 .WillByDefault(Return(content::DOWNLOAD_INTERRUPT_REASON_NONE
));
313 ON_CALL(*item
, GetMimeType())
314 .WillByDefault(Return(test_case
.mime_type
));
315 ON_CALL(*item
, GetReferrerUrl())
316 .WillByDefault(ReturnRefOfCopy(download_url
));
317 ON_CALL(*item
, GetState())
318 .WillByDefault(Return(DownloadItem::IN_PROGRESS
));
319 ON_CALL(*item
, GetTargetDisposition())
320 .WillByDefault(Return(initial_disposition
));
321 ON_CALL(*item
, GetTargetFilePath())
322 .WillByDefault(ReturnRefOfCopy(base::FilePath()));
323 ON_CALL(*item
, GetTransitionType())
324 .WillByDefault(Return(ui::PAGE_TRANSITION_LINK
));
325 ON_CALL(*item
, GetURL())
326 .WillByDefault(ReturnRefOfCopy(download_url
));
327 ON_CALL(*item
, GetUrlChain())
328 .WillByDefault(ReturnRefOfCopy(url_chain
));
329 ON_CALL(*item
, GetWebContents())
330 .WillByDefault(Return(web_contents()));
331 ON_CALL(*item
, HasUserGesture())
332 .WillByDefault(Return(true));
333 ON_CALL(*item
, IsDangerous())
334 .WillByDefault(Return(false));
335 ON_CALL(*item
, IsTemporary())
336 .WillByDefault(Return(false));
340 void DownloadTargetDeterminerTest::EnableAutoOpenBasedOnExtension(
341 const base::FilePath
& path
) {
342 EXPECT_TRUE(download_prefs_
->EnableAutoOpenBasedOnExtension(path
));
345 void DownloadTargetDeterminerTest::SetManagedDownloadPath(
346 const base::FilePath
& path
) {
347 profile()->GetTestingPrefService()->
348 SetManagedPref(prefs::kDownloadDefaultDirectory
,
349 base::CreateFilePathValue(path
));
352 void DownloadTargetDeterminerTest::SetPromptForDownload(bool prompt
) {
353 profile()->GetTestingPrefService()->
354 SetBoolean(prefs::kPromptForDownload
, prompt
);
357 base::FilePath
DownloadTargetDeterminerTest::GetPathInDownloadDir(
358 const base::FilePath::StringType
& relative_path
) {
359 if (relative_path
.empty())
360 return base::FilePath();
361 base::FilePath
full_path(test_download_dir().Append(relative_path
));
362 return full_path
.NormalizePathSeparators();
365 void DownloadTargetDeterminerTest::RunTestCase(
366 const DownloadTestCase
& test_case
,
367 const base::FilePath
& initial_virtual_path
,
368 content::MockDownloadItem
* item
) {
369 scoped_ptr
<DownloadTargetInfo
> target_info
=
370 RunDownloadTargetDeterminer(initial_virtual_path
, item
);
371 VerifyDownloadTarget(test_case
, target_info
.get());
374 void CompletionCallbackWrapper(
375 const base::Closure
& closure
,
376 scoped_ptr
<DownloadTargetInfo
>* target_info_receiver
,
377 scoped_ptr
<DownloadTargetInfo
> target_info
) {
378 target_info_receiver
->swap(target_info
);
379 base::MessageLoop::current()->PostTask(FROM_HERE
, closure
);
382 scoped_ptr
<DownloadTargetInfo
>
383 DownloadTargetDeterminerTest::RunDownloadTargetDeterminer(
384 const base::FilePath
& initial_virtual_path
,
385 content::MockDownloadItem
* item
) {
386 scoped_ptr
<DownloadTargetInfo
> target_info
;
387 base::RunLoop run_loop
;
388 DownloadTargetDeterminer::Start(
389 item
, initial_virtual_path
, download_prefs_
.get(), delegate(),
390 base::Bind(&CompletionCallbackWrapper
,
391 run_loop
.QuitClosure(),
394 ::testing::Mock::VerifyAndClearExpectations(delegate());
395 return target_info
.Pass();
398 void DownloadTargetDeterminerTest::RunTestCasesWithActiveItem(
399 const DownloadTestCase test_cases
[],
400 size_t test_case_count
) {
401 for (size_t i
= 0; i
< test_case_count
; ++i
) {
402 scoped_ptr
<content::MockDownloadItem
> item(
403 CreateActiveDownloadItem(i
, test_cases
[i
]));
404 SCOPED_TRACE(testing::Message() << "Running test case " << i
);
405 RunTestCase(test_cases
[i
], base::FilePath(), item
.get());
409 void DownloadTargetDeterminerTest::VerifyDownloadTarget(
410 const DownloadTestCase
& test_case
,
411 const DownloadTargetInfo
* target_info
) {
412 base::FilePath
expected_local_path(
413 GetPathInDownloadDir(test_case
.expected_local_path
));
414 EXPECT_EQ(expected_local_path
.value(), target_info
->target_path
.value());
415 EXPECT_EQ(test_case
.expected_disposition
, target_info
->target_disposition
);
416 EXPECT_EQ(test_case
.expected_danger_type
, target_info
->danger_type
);
418 switch (test_case
.expected_intermediate
) {
419 case EXPECT_CRDOWNLOAD
:
420 EXPECT_EQ(DownloadTargetDeterminer::GetCrDownloadPath(
421 target_info
->target_path
).value(),
422 target_info
->intermediate_path
.value());
425 case EXPECT_UNCONFIRMED
:
426 // The paths (in English) look like: /path/Unconfirmed xxx.crdownload.
427 // Of this, we only check that the path is:
428 // 1. Not "/path/target.crdownload",
429 // 2. Points to the same directory as the target.
430 // 3. Has extension ".crdownload".
431 // 4. Basename starts with "Unconfirmed ".
432 EXPECT_NE(DownloadTargetDeterminer::GetCrDownloadPath(expected_local_path
)
434 target_info
->intermediate_path
.value());
435 EXPECT_EQ(expected_local_path
.DirName().value(),
436 target_info
->intermediate_path
.DirName().value());
437 EXPECT_TRUE(target_info
->intermediate_path
.MatchesExtension(
438 FILE_PATH_LITERAL(".crdownload")));
440 target_info
->intermediate_path
.BaseName().value().find(
441 FILE_PATH_LITERAL("Unconfirmed ")));
444 case EXPECT_LOCAL_PATH
:
445 EXPECT_EQ(expected_local_path
.value(),
446 target_info
->intermediate_path
.value());
452 void MockDownloadTargetDeterminerDelegate::NullReserveVirtualPath(
453 DownloadItem
* download
,
454 const base::FilePath
& virtual_path
,
455 bool create_directory
,
456 DownloadPathReservationTracker::FilenameConflictAction conflict_action
,
457 const DownloadTargetDeterminerDelegate::ReservedPathCallback
& callback
) {
458 callback
.Run(virtual_path
, true);
462 void MockDownloadTargetDeterminerDelegate::NullPromptUser(
463 DownloadItem
* download
, const base::FilePath
& suggested_path
,
464 const FileSelectedCallback
& callback
) {
465 callback
.Run(suggested_path
);
469 void MockDownloadTargetDeterminerDelegate::NullDetermineLocalPath(
470 DownloadItem
* download
, const base::FilePath
& virtual_path
,
471 const LocalPathCallback
& callback
) {
472 callback
.Run(virtual_path
);
475 // NotifyExtensions implementation that overrides the path so that the target
476 // file is in a subdirectory called 'overridden'. If the extension is '.remove',
477 // the extension is removed.
478 void NotifyExtensionsOverridePath(
479 content::DownloadItem
* download
,
480 const base::FilePath
& path
,
481 const DownloadTargetDeterminerDelegate::NotifyExtensionsCallback
&
483 base::FilePath new_path
=
485 .AppendASCII("overridden")
486 .Append(path
.BaseName());
487 if (new_path
.MatchesExtension(FILE_PATH_LITERAL(".remove")))
488 new_path
= new_path
.RemoveExtension();
489 callback
.Run(new_path
, DownloadPathReservationTracker::UNIQUIFY
);
492 void CheckDownloadUrlCheckExes(
493 content::DownloadItem
* download
,
494 const base::FilePath
& path
,
495 const DownloadTargetDeterminerDelegate::CheckDownloadUrlCallback
&
497 if (path
.MatchesExtension(FILE_PATH_LITERAL(".exe")))
498 callback
.Run(content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT
);
500 callback
.Run(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
);
503 TEST_F(DownloadTargetDeterminerTest
, TargetDeterminer_Basic
) {
504 const DownloadTestCase kBasicTestCases
[] = {
508 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
509 "http://example.com/foo.txt", "text/plain",
510 FILE_PATH_LITERAL(""),
512 FILE_PATH_LITERAL("foo.txt"),
513 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
521 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
522 "http://example.com/foo.txt", "text/plain",
523 FILE_PATH_LITERAL(""),
525 FILE_PATH_LITERAL("foo.txt"),
526 DownloadItem::TARGET_DISPOSITION_PROMPT
,
532 // 2: Automatic Dangerous
534 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE
,
535 "http://example.com/foo.crx", "",
536 FILE_PATH_LITERAL(""),
538 FILE_PATH_LITERAL("foo.crx"),
539 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
547 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
548 "http://example.com/foo.txt", "",
549 FILE_PATH_LITERAL("forced-foo.txt"),
551 FILE_PATH_LITERAL("forced-foo.txt"),
552 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
558 // The test assumes that .crx files have a danger level of
559 // ALLOW_ON_USER_GESTURE.
560 ASSERT_EQ(download_util::ALLOW_ON_USER_GESTURE
,
561 download_util::GetFileDangerLevel(
562 base::FilePath(FILE_PATH_LITERAL("foo.crx"))));
563 RunTestCasesWithActiveItem(kBasicTestCases
, arraysize(kBasicTestCases
));
566 TEST_F(DownloadTargetDeterminerTest
, TargetDeterminer_CancelSaveAs
) {
567 const DownloadTestCase kCancelSaveAsTestCases
[] = {
569 // 0: Save_As Safe, Cancelled.
571 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
572 "http://example.com/foo.txt", "text/plain",
573 FILE_PATH_LITERAL(""),
575 FILE_PATH_LITERAL(""),
576 DownloadItem::TARGET_DISPOSITION_PROMPT
,
581 ON_CALL(*delegate(), PromptUserForDownloadPath(_
, _
, _
))
582 .WillByDefault(WithArg
<2>(ScheduleCallback(base::FilePath())));
583 RunTestCasesWithActiveItem(kCancelSaveAsTestCases
,
584 arraysize(kCancelSaveAsTestCases
));
587 // The SafeBrowsing check is performed early. Make sure that a download item
588 // that has been marked as DANGEROUS_URL behaves correctly.
589 TEST_F(DownloadTargetDeterminerTest
, TargetDeterminer_DangerousUrl
) {
590 const DownloadTestCase kSafeBrowsingTestCases
[] = {
592 // 0: Automatic Dangerous URL
594 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL
,
595 "http://phishing.example.com/foo.txt", "",
596 FILE_PATH_LITERAL(""),
598 FILE_PATH_LITERAL("foo.txt"),
599 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
605 // 1: Save As Dangerous URL
607 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL
,
608 "http://phishing.example.com/foo.txt", "",
609 FILE_PATH_LITERAL(""),
611 FILE_PATH_LITERAL("foo.txt"),
612 DownloadItem::TARGET_DISPOSITION_PROMPT
,
618 // 2: Forced Dangerous URL
620 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL
,
621 "http://phishing.example.com/foo.txt", "",
622 FILE_PATH_LITERAL("forced-foo.txt"),
624 FILE_PATH_LITERAL("forced-foo.txt"),
625 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
631 // 3: Automatic Dangerous URL + Dangerous file. Dangerous URL takes
634 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL
,
635 "http://phishing.example.com/foo.html", "",
636 FILE_PATH_LITERAL(""),
638 FILE_PATH_LITERAL("foo.html"),
639 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
645 // 4: Save As Dangerous URL + Dangerous file
647 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL
,
648 "http://phishing.example.com/foo.html", "",
649 FILE_PATH_LITERAL(""),
651 FILE_PATH_LITERAL("foo.html"),
652 DownloadItem::TARGET_DISPOSITION_PROMPT
,
658 // 5: Forced Dangerous URL + Dangerous file
660 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL
,
661 "http://phishing.example.com/foo.html", "",
662 FILE_PATH_LITERAL("forced-foo.html"),
664 FILE_PATH_LITERAL("forced-foo.html"),
665 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
671 ON_CALL(*delegate(), CheckDownloadUrl(_
, _
, _
))
672 .WillByDefault(WithArg
<2>(ScheduleCallback(
673 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL
)));
674 RunTestCasesWithActiveItem(kSafeBrowsingTestCases
,
675 arraysize(kSafeBrowsingTestCases
));
678 // The SafeBrowsing check is performed early. Make sure that a download item
679 // that has been marked as MAYBE_DANGEROUS_CONTENT behaves correctly.
680 TEST_F(DownloadTargetDeterminerTest
, TargetDeterminer_MaybeDangerousContent
) {
681 const DownloadTestCase kSafeBrowsingTestCases
[] = {
683 // 0: Automatic Maybe dangerous content
685 content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT
,
686 "http://phishing.example.com/foo.exe", "",
687 FILE_PATH_LITERAL(""),
689 FILE_PATH_LITERAL("foo.exe"),
690 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
696 // 1: Save As Maybe dangerous content
698 content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT
,
699 "http://phishing.example.com/foo.exe", "",
700 FILE_PATH_LITERAL(""),
702 FILE_PATH_LITERAL("foo.exe"),
703 DownloadItem::TARGET_DISPOSITION_PROMPT
,
709 // 2: Forced Maybe dangerous content
711 content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT
,
712 "http://phishing.example.com/foo.exe", "",
713 FILE_PATH_LITERAL("forced-foo.exe"),
715 FILE_PATH_LITERAL("forced-foo.exe"),
716 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
722 ON_CALL(*delegate(), CheckDownloadUrl(_
, _
, _
))
723 .WillByDefault(WithArg
<2>(ScheduleCallback(
724 content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT
)));
725 RunTestCasesWithActiveItem(kSafeBrowsingTestCases
,
726 arraysize(kSafeBrowsingTestCases
));
729 // Test whether the last saved directory is used for 'Save As' downloads.
730 TEST_F(DownloadTargetDeterminerTest
, TargetDeterminer_LastSavePath
) {
731 const DownloadTestCase kLastSavePathTestCasesPre
[] = {
733 // 0: If the last save path is empty, then the default download directory
736 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
737 "http://example.com/foo.txt", "text/plain",
738 FILE_PATH_LITERAL(""),
740 FILE_PATH_LITERAL("foo.txt"),
741 DownloadItem::TARGET_DISPOSITION_PROMPT
,
747 // These test cases are run with a last save path set to a non-emtpy local
748 // download directory.
749 const DownloadTestCase kLastSavePathTestCasesPost
[] = {
751 // 0: This test case is run with the last download directory set to
752 // '<test_download_dir()>/foo'.
754 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
755 "http://example.com/foo.txt", "text/plain",
756 FILE_PATH_LITERAL(""),
758 FILE_PATH_LITERAL("foo/foo.txt"),
759 DownloadItem::TARGET_DISPOSITION_PROMPT
,
765 // 1: Start an automatic download. This should be saved to the user's
766 // default download directory and not the last used Save As directory.
768 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
769 "http://example.com/foo.txt", "text/plain",
770 FILE_PATH_LITERAL(""),
772 FILE_PATH_LITERAL("foo.txt"),
773 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
779 // This test case is run with the last save path set to a non-empty virtual
781 const DownloadTestCase kLastSavePathTestCasesVirtual
[] = {
784 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
785 "http://example.com/foo.txt", "text/plain",
786 FILE_PATH_LITERAL(""),
788 FILE_PATH_LITERAL("bar.txt"),
789 DownloadItem::TARGET_DISPOSITION_PROMPT
,
796 SCOPED_TRACE(testing::Message()
797 << "Running with default download path");
798 base::FilePath prompt_path
=
799 GetPathInDownloadDir(FILE_PATH_LITERAL("foo.txt"));
800 EXPECT_CALL(*delegate(), PromptUserForDownloadPath(_
, prompt_path
, _
));
801 RunTestCasesWithActiveItem(kLastSavePathTestCasesPre
,
802 arraysize(kLastSavePathTestCasesPre
));
805 // Try with a non-empty last save path.
807 SCOPED_TRACE(testing::Message()
808 << "Running with local last_selected_directory");
809 download_prefs()->SetSaveFilePath(test_download_dir().AppendASCII("foo"));
810 base::FilePath prompt_path
=
811 GetPathInDownloadDir(FILE_PATH_LITERAL("foo/foo.txt"));
812 EXPECT_CALL(*delegate(), PromptUserForDownloadPath(_
, prompt_path
, _
));
813 RunTestCasesWithActiveItem(kLastSavePathTestCasesPost
,
814 arraysize(kLastSavePathTestCasesPost
));
817 // And again, but this time use a virtual directory.
819 SCOPED_TRACE(testing::Message()
820 << "Running with virtual last_selected_directory");
821 base::FilePath last_selected_dir
= test_virtual_dir().AppendASCII("foo");
822 base::FilePath virtual_path
= last_selected_dir
.AppendASCII("foo.txt");
823 download_prefs()->SetSaveFilePath(last_selected_dir
);
824 EXPECT_CALL(*delegate(), PromptUserForDownloadPath(
825 _
, last_selected_dir
.AppendASCII("foo.txt"), _
));
826 EXPECT_CALL(*delegate(), DetermineLocalPath(_
, virtual_path
, _
))
827 .WillOnce(WithArg
<2>(ScheduleCallback(
828 GetPathInDownloadDir(FILE_PATH_LITERAL("bar.txt")))));
829 RunTestCasesWithActiveItem(kLastSavePathTestCasesVirtual
,
830 arraysize(kLastSavePathTestCasesVirtual
));
834 // These tests are run with the default downloads folder set to a virtual
836 TEST_F(DownloadTargetDeterminerTest
, TargetDeterminer_DefaultVirtual
) {
837 // The default download directory is the virutal path.
838 download_prefs()->SetDownloadPath(test_virtual_dir());
841 SCOPED_TRACE(testing::Message() << "Automatic Safe Download");
842 const DownloadTestCase kAutomaticDownloadToVirtualDir
= {
844 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
845 "http://example.com/foo.txt", "text/plain",
846 FILE_PATH_LITERAL(""),
848 FILE_PATH_LITERAL("foo-local.txt"),
849 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
853 EXPECT_CALL(*delegate(), DetermineLocalPath(_
, _
, _
))
854 .WillOnce(WithArg
<2>(ScheduleCallback(
855 GetPathInDownloadDir(FILE_PATH_LITERAL("foo-local.txt")))));
856 RunTestCasesWithActiveItem(&kAutomaticDownloadToVirtualDir
, 1);
860 SCOPED_TRACE(testing::Message() << "Save As to virtual directory");
861 const DownloadTestCase kSaveAsToVirtualDir
= {
863 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
864 "http://example.com/bar.txt", "text/plain",
865 FILE_PATH_LITERAL(""),
867 FILE_PATH_LITERAL("foo-local.txt"),
868 DownloadItem::TARGET_DISPOSITION_PROMPT
,
872 EXPECT_CALL(*delegate(), DetermineLocalPath(_
, _
, _
))
873 .WillOnce(WithArg
<2>(ScheduleCallback(
874 GetPathInDownloadDir(FILE_PATH_LITERAL("foo-local.txt")))));
875 EXPECT_CALL(*delegate(), PromptUserForDownloadPath(
876 _
, test_virtual_dir().AppendASCII("bar.txt"), _
))
877 .WillOnce(WithArg
<2>(ScheduleCallback(
878 test_virtual_dir().AppendASCII("prompted.txt"))));
879 RunTestCasesWithActiveItem(&kSaveAsToVirtualDir
, 1);
883 SCOPED_TRACE(testing::Message() << "Save As to local directory");
884 const DownloadTestCase kSaveAsToLocalDir
= {
886 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
887 "http://example.com/bar.txt", "text/plain",
888 FILE_PATH_LITERAL(""),
890 FILE_PATH_LITERAL("foo-x.txt"),
891 DownloadItem::TARGET_DISPOSITION_PROMPT
,
895 EXPECT_CALL(*delegate(), PromptUserForDownloadPath(
896 _
, test_virtual_dir().AppendASCII("bar.txt"), _
))
897 .WillOnce(WithArg
<2>(ScheduleCallback(
898 GetPathInDownloadDir(FILE_PATH_LITERAL("foo-x.txt")))));
899 RunTestCasesWithActiveItem(&kSaveAsToLocalDir
, 1);
903 SCOPED_TRACE(testing::Message() << "Forced safe download");
904 const DownloadTestCase kForcedSafe
= {
906 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
907 "http://example.com/foo.txt", "",
908 FILE_PATH_LITERAL("forced-foo.txt"),
910 FILE_PATH_LITERAL("forced-foo.txt"),
911 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
915 RunTestCasesWithActiveItem(&kForcedSafe
, 1);
919 // Test that an inactive download will still get a virtual or local download
921 TEST_F(DownloadTargetDeterminerTest
, TargetDeterminer_InactiveDownload
) {
922 const DownloadTestCase kInactiveTestCases
[] = {
925 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
926 "http://example.com/foo.txt", "text/plain",
927 FILE_PATH_LITERAL(""),
929 FILE_PATH_LITERAL(""),
930 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
937 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
938 "http://example.com/foo.txt", "text/plain",
939 FILE_PATH_LITERAL(""),
941 FILE_PATH_LITERAL(""),
942 DownloadItem::TARGET_DISPOSITION_PROMPT
,
948 for (size_t i
= 0; i
< arraysize(kInactiveTestCases
); ++i
) {
949 SCOPED_TRACE(testing::Message() << "Running test case " << i
);
950 const DownloadTestCase
& test_case
= kInactiveTestCases
[i
];
951 scoped_ptr
<content::MockDownloadItem
> item(
952 CreateActiveDownloadItem(i
, test_case
));
953 EXPECT_CALL(*item
.get(), GetState())
954 .WillRepeatedly(Return(content::DownloadItem::CANCELLED
));
955 // Even though one is a SAVE_AS download, no prompt will be displayed to
956 // the user because the download is inactive.
957 EXPECT_CALL(*delegate(), PromptUserForDownloadPath(_
, _
, _
))
959 RunTestCase(test_case
, base::FilePath(), item
.get());
963 // If the reserved path could not be verified, then the user should see a
965 TEST_F(DownloadTargetDeterminerTest
, TargetDeterminer_ReservationFailed
) {
966 const DownloadTestCase kReservationFailedCases
[] = {
968 // 0: Automatic download. Since the reservation fails, the disposition of
969 // the target is to prompt, but the returned path is used.
971 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
972 "http://example.com/foo.txt", "text/plain",
973 FILE_PATH_LITERAL(""),
975 FILE_PATH_LITERAL("bar.txt"),
976 DownloadItem::TARGET_DISPOSITION_PROMPT
,
982 // Setup ReserveVirtualPath() to fail.
983 ON_CALL(*delegate(), ReserveVirtualPath(_
, _
, _
, _
, _
))
984 .WillByDefault(WithArg
<4>(ScheduleCallback2(
985 GetPathInDownloadDir(FILE_PATH_LITERAL("bar.txt")), false)));
986 RunTestCasesWithActiveItem(kReservationFailedCases
,
987 arraysize(kReservationFailedCases
));
990 // If the local path could not be determined, the download should be cancelled.
991 TEST_F(DownloadTargetDeterminerTest
, TargetDeterminer_LocalPathFailed
) {
992 const DownloadTestCase kLocalPathFailedCases
[] = {
994 // 0: Automatic download.
996 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
997 "http://example.com/foo.txt", "text/plain",
998 FILE_PATH_LITERAL(""),
1000 FILE_PATH_LITERAL(""),
1001 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
1007 // The default download directory is the virtual path.
1008 download_prefs()->SetDownloadPath(test_virtual_dir());
1009 // Simulate failed call to DetermineLocalPath.
1010 EXPECT_CALL(*delegate(), DetermineLocalPath(
1011 _
, GetPathInDownloadDir(FILE_PATH_LITERAL("virtual/foo.txt")), _
))
1012 .WillOnce(WithArg
<2>(ScheduleCallback(base::FilePath())));
1013 RunTestCasesWithActiveItem(kLocalPathFailedCases
,
1014 arraysize(kLocalPathFailedCases
));
1017 // Downloads that have a danger level of ALLOW_ON_USER_GESTURE should be marked
1018 // as safe depending on whether there was a user gesture associated with the
1019 // download and whether the referrer was visited prior to today.
1020 TEST_F(DownloadTargetDeterminerTest
, TargetDeterminer_VisitedReferrer
) {
1021 const DownloadTestCase kVisitedReferrerCases
[] = {
1022 // http://visited.example.com/ is added to the history as a visit that
1023 // happened prior to today.
1025 // 0: Safe download due to visiting referrer before.
1027 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
1028 "http://visited.example.com/foo.crx", "application/xml",
1029 FILE_PATH_LITERAL(""),
1031 FILE_PATH_LITERAL("foo.crx"),
1032 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
1038 // 1: Dangerous due to not having visited referrer before.
1040 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE
,
1041 "http://not-visited.example.com/foo.crx", "application/xml",
1042 FILE_PATH_LITERAL(""),
1044 FILE_PATH_LITERAL("foo.crx"),
1045 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
1051 // 2: Safe because the user is being prompted.
1053 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
1054 "http://not-visited.example.com/foo.crx", "application/xml",
1055 FILE_PATH_LITERAL(""),
1057 FILE_PATH_LITERAL("foo.crx"),
1058 DownloadItem::TARGET_DISPOSITION_PROMPT
,
1064 // 3: Safe because of forced path.
1066 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
1067 "http://not-visited.example.com/foo.crx", "application/xml",
1068 FILE_PATH_LITERAL("foo.crx"),
1070 FILE_PATH_LITERAL("foo.crx"),
1071 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
1077 // This test assumes that the danger level of .crx files is
1078 // ALLOW_ON_USER_GESTURE.
1079 ASSERT_EQ(download_util::ALLOW_ON_USER_GESTURE
,
1080 download_util::GetFileDangerLevel(
1081 base::FilePath(FILE_PATH_LITERAL("foo.crx"))));
1083 // First the history service must exist.
1084 ASSERT_TRUE(profile()->CreateHistoryService(false, false));
1086 GURL
url("http://visited.example.com/visited-link.html");
1087 // The time of visit is picked to be several seconds prior to the most recent
1089 base::Time
time_of_visit(
1090 base::Time::Now().LocalMidnight() - base::TimeDelta::FromSeconds(10));
1091 HistoryService
* history_service
= HistoryServiceFactory::GetForProfile(
1092 profile(), ServiceAccessType::EXPLICIT_ACCESS
);
1093 ASSERT_TRUE(history_service
);
1094 history_service
->AddPage(url
, time_of_visit
, history::SOURCE_BROWSED
);
1096 RunTestCasesWithActiveItem(kVisitedReferrerCases
,
1097 arraysize(kVisitedReferrerCases
));
1100 // These test cases are run with "Prompt for download" user preference set to
1102 TEST_F(DownloadTargetDeterminerTest
, TargetDeterminer_PromptAlways
) {
1103 const DownloadTestCase kPromptingTestCases
[] = {
1105 // 0: Safe Automatic - Should prompt because of "Prompt for download"
1106 // preference setting.
1108 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
1109 "http://example.com/foo.txt", "text/plain",
1110 FILE_PATH_LITERAL(""),
1112 FILE_PATH_LITERAL("foo.txt"),
1113 DownloadItem::TARGET_DISPOSITION_PROMPT
,
1119 // 1: Safe Forced - Shouldn't prompt.
1121 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
1122 "http://example.com/foo.txt", "text/plain",
1123 FILE_PATH_LITERAL("foo.txt"),
1125 FILE_PATH_LITERAL("foo.txt"),
1126 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
1132 // 2: Automatic - The filename extension is marked as one that we will
1133 // open automatically. Shouldn't prompt.
1135 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
1136 "http://example.com/foo.dummy", "",
1137 FILE_PATH_LITERAL(""),
1139 FILE_PATH_LITERAL("foo.dummy"),
1140 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
1146 SetPromptForDownload(true);
1147 EnableAutoOpenBasedOnExtension(
1148 base::FilePath(FILE_PATH_LITERAL("dummy.dummy")));
1149 RunTestCasesWithActiveItem(kPromptingTestCases
,
1150 arraysize(kPromptingTestCases
));
1153 #if defined(ENABLE_EXTENSIONS)
1154 // These test cases are run with "Prompt for download" user preference set to
1155 // true. Automatic extension downloads shouldn't cause prompting.
1156 // Android doesn't support extensions.
1157 TEST_F(DownloadTargetDeterminerTest
, TargetDeterminer_PromptAlways_Extension
) {
1158 const DownloadTestCase kPromptingTestCases
[] = {
1160 // 0: Automatic Browser Extension download. - Shouldn't prompt for browser
1161 // extension downloads even if "Prompt for download" preference is set.
1163 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE
,
1164 "http://example.com/foo.crx",
1165 extensions::Extension::kMimeType
,
1166 FILE_PATH_LITERAL(""),
1168 FILE_PATH_LITERAL("foo.crx"),
1169 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
1176 // 1: Automatic User Script - Shouldn't prompt for user script downloads
1177 // even if "Prompt for download" preference is set. ".js" files are
1178 // considered dangerous on Windows.
1180 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE
,
1181 "http://example.com/foo.user.js", "",
1182 FILE_PATH_LITERAL(""),
1184 FILE_PATH_LITERAL("foo.user.js"),
1185 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
1191 // 1: Automatic User Script - Shouldn't prompt for user script downloads
1192 // even if "Prompt for download" preference is set.
1194 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
1195 "http://example.com/foo.user.js", "",
1196 FILE_PATH_LITERAL(""),
1198 FILE_PATH_LITERAL("foo.user.js"),
1199 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
1206 SetPromptForDownload(true);
1207 RunTestCasesWithActiveItem(kPromptingTestCases
,
1208 arraysize(kPromptingTestCases
));
1210 #endif // defined(ENABLE_EXTENSIONS)
1212 // If the download path is managed, then we don't show any prompts.
1213 // Note that if the download path is managed, then PromptForDownload() is false.
1214 TEST_F(DownloadTargetDeterminerTest
, TargetDeterminer_ManagedPath
) {
1215 const DownloadTestCase kManagedPathTestCases
[] = {
1217 // 0: Automatic Safe
1219 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
1220 "http://example.com/foo.txt", "text/plain",
1221 FILE_PATH_LITERAL(""),
1223 FILE_PATH_LITERAL("foo.txt"),
1224 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
1232 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
1233 "http://example.com/foo.txt", "text/plain",
1234 FILE_PATH_LITERAL(""),
1236 FILE_PATH_LITERAL("foo.txt"),
1237 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
1243 SetManagedDownloadPath(test_download_dir());
1244 ASSERT_TRUE(download_prefs()->IsDownloadPathManaged());
1245 RunTestCasesWithActiveItem(kManagedPathTestCases
,
1246 arraysize(kManagedPathTestCases
));
1249 // Test basic functionality supporting extensions that want to override download
1251 TEST_F(DownloadTargetDeterminerTest
, TargetDeterminer_NotifyExtensionsSafe
) {
1252 const DownloadTestCase kNotifyExtensionsTestCases
[] = {
1254 // 0: Automatic Safe
1256 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
1257 "http://example.com/foo.txt", "text/plain",
1258 FILE_PATH_LITERAL(""),
1260 FILE_PATH_LITERAL("overridden/foo.txt"),
1261 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
1269 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
1270 "http://example.com/foo.txt", "text/plain",
1271 FILE_PATH_LITERAL(""),
1273 FILE_PATH_LITERAL("overridden/foo.txt"),
1274 DownloadItem::TARGET_DISPOSITION_PROMPT
,
1280 // 2: Automatic Dangerous
1282 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE
,
1283 "http://example.com/foo.crx", "",
1284 FILE_PATH_LITERAL(""),
1286 FILE_PATH_LITERAL("overridden/foo.crx"),
1287 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
1295 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
1296 "http://example.com/foo.txt", "",
1297 FILE_PATH_LITERAL("forced-foo.txt"),
1299 FILE_PATH_LITERAL("forced-foo.txt"),
1300 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
1306 ON_CALL(*delegate(), NotifyExtensions(_
, _
, _
))
1307 .WillByDefault(Invoke(&NotifyExtensionsOverridePath
));
1308 RunTestCasesWithActiveItem(kNotifyExtensionsTestCases
,
1309 arraysize(kNotifyExtensionsTestCases
));
1312 // Test that filenames provided by extensions are passed into SafeBrowsing
1313 // checks and dangerous download checks.
1314 TEST_F(DownloadTargetDeterminerTest
, TargetDeterminer_NotifyExtensionsUnsafe
) {
1315 const DownloadTestCase kNotifyExtensionsTestCases
[] = {
1317 // 0: Automatic Safe : Later overridden by a dangerous filetype.
1319 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE
,
1320 "http://example.com/foo.crx.remove", "text/plain",
1321 FILE_PATH_LITERAL(""),
1323 FILE_PATH_LITERAL("overridden/foo.crx"),
1324 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
1330 // 1: Automatic Safe : Later overridden by a potentially dangerous
1333 content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT
,
1334 "http://example.com/foo.exe.remove", "text/plain",
1335 FILE_PATH_LITERAL(""),
1337 FILE_PATH_LITERAL("overridden/foo.exe"),
1338 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
1344 ON_CALL(*delegate(), NotifyExtensions(_
, _
, _
))
1345 .WillByDefault(Invoke(&NotifyExtensionsOverridePath
));
1346 ON_CALL(*delegate(), CheckDownloadUrl(_
, _
, _
))
1347 .WillByDefault(Invoke(&CheckDownloadUrlCheckExes
));
1348 RunTestCasesWithActiveItem(kNotifyExtensionsTestCases
,
1349 arraysize(kNotifyExtensionsTestCases
));
1352 // Test that conflict actions set by extensions are passed correctly into
1353 // ReserveVirtualPath.
1354 TEST_F(DownloadTargetDeterminerTest
,
1355 TargetDeterminer_NotifyExtensionsConflict
) {
1356 const DownloadTestCase kNotifyExtensionsTestCase
= {
1358 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
1359 "http://example.com/foo.txt", "text/plain",
1360 FILE_PATH_LITERAL(""),
1362 FILE_PATH_LITERAL("overridden/foo.txt"),
1363 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
1368 const DownloadTestCase
& test_case
= kNotifyExtensionsTestCase
;
1369 scoped_ptr
<content::MockDownloadItem
> item(
1370 CreateActiveDownloadItem(0, test_case
));
1371 base::FilePath
overridden_path(FILE_PATH_LITERAL("overridden/foo.txt"));
1372 base::FilePath full_overridden_path
=
1373 GetPathInDownloadDir(overridden_path
.value());
1375 // First case: An extension sets the conflict_action to OVERWRITE.
1376 EXPECT_CALL(*delegate(), NotifyExtensions(_
, _
, _
))
1377 .WillOnce(WithArg
<2>(
1378 ScheduleCallback2(overridden_path
,
1379 DownloadPathReservationTracker::OVERWRITE
)));
1380 EXPECT_CALL(*delegate(), ReserveVirtualPath(
1381 _
, full_overridden_path
, true, DownloadPathReservationTracker::OVERWRITE
,
1382 _
)).WillOnce(WithArg
<4>(
1383 ScheduleCallback2(full_overridden_path
, true)));
1385 RunTestCase(test_case
, base::FilePath(), item
.get());
1387 // Second case: An extension sets the conflict_action to PROMPT.
1388 EXPECT_CALL(*delegate(), NotifyExtensions(_
, _
, _
))
1389 .WillOnce(WithArg
<2>(
1390 ScheduleCallback2(overridden_path
,
1391 DownloadPathReservationTracker::PROMPT
)));
1392 EXPECT_CALL(*delegate(), ReserveVirtualPath(
1393 _
, full_overridden_path
, true, DownloadPathReservationTracker::PROMPT
, _
))
1394 .WillOnce(WithArg
<4>(
1395 ScheduleCallback2(full_overridden_path
, true)));
1396 RunTestCase(test_case
, base::FilePath(), item
.get());
1399 // Test that relative paths returned by extensions are always relative to the
1400 // default downloads path.
1401 TEST_F(DownloadTargetDeterminerTest
,
1402 TargetDeterminer_NotifyExtensionsDefaultPath
) {
1403 const DownloadTestCase kNotifyExtensionsTestCase
= {
1405 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
1406 "http://example.com/foo.txt", "text/plain",
1407 FILE_PATH_LITERAL(""),
1409 FILE_PATH_LITERAL("overridden/foo.txt"),
1410 DownloadItem::TARGET_DISPOSITION_PROMPT
,
1415 const DownloadTestCase
& test_case
= kNotifyExtensionsTestCase
;
1416 scoped_ptr
<content::MockDownloadItem
> item(
1417 CreateActiveDownloadItem(0, test_case
));
1418 base::FilePath
overridden_path(FILE_PATH_LITERAL("overridden/foo.txt"));
1419 base::FilePath full_overridden_path
=
1420 GetPathInDownloadDir(overridden_path
.value());
1422 download_prefs()->SetSaveFilePath(GetPathInDownloadDir(
1423 FILE_PATH_LITERAL("last_selected")));
1425 EXPECT_CALL(*delegate(), NotifyExtensions(_
, _
, _
))
1426 .WillOnce(WithArg
<2>(
1427 ScheduleCallback2(overridden_path
,
1428 DownloadPathReservationTracker::UNIQUIFY
)));
1429 EXPECT_CALL(*delegate(),
1430 PromptUserForDownloadPath(_
, full_overridden_path
, _
))
1431 .WillOnce(WithArg
<2>(
1432 ScheduleCallback(full_overridden_path
)));
1433 RunTestCase(test_case
, base::FilePath(), item
.get());
1436 TEST_F(DownloadTargetDeterminerTest
,
1437 TargetDeterminer_InitialVirtualPathUnsafe
) {
1438 const base::FilePath::CharType
* kInitialPath
=
1439 FILE_PATH_LITERAL("some_path/bar.html");
1441 const DownloadTestCase kInitialPathTestCase
= {
1442 // 0: Save As Save. The path generated based on the DownloadItem is safe,
1443 // but the initial path is unsafe. However, the download is not considered
1444 // dangerous since the user has been prompted.
1446 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
1447 "http://example.com/foo.txt", "text/plain",
1448 FILE_PATH_LITERAL(""),
1451 DownloadItem::TARGET_DISPOSITION_PROMPT
,
1456 const DownloadTestCase
& test_case
= kInitialPathTestCase
;
1457 scoped_ptr
<content::MockDownloadItem
> item(
1458 CreateActiveDownloadItem(1, test_case
));
1459 EXPECT_CALL(*item
, GetLastReason())
1460 .WillRepeatedly(Return(
1461 content::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED
));
1462 EXPECT_CALL(*item
, GetTargetDisposition())
1463 .WillRepeatedly(Return(DownloadItem::TARGET_DISPOSITION_PROMPT
));
1464 RunTestCase(test_case
, GetPathInDownloadDir(kInitialPath
), item
.get());
1467 // Prompting behavior for resumed downloads is based on the last interrupt
1468 // reason. If the reason indicates that the target path may not be suitable for
1469 // the download (ACCESS_DENIED, NO_SPACE, etc..), then the user should be
1470 // prompted, and not otherwise. These test cases shouldn't result in prompting
1471 // since the error is set to NETWORK_FAILED.
1472 TEST_F(DownloadTargetDeterminerTest
, TargetDeterminer_ResumedNoPrompt
) {
1473 // All test cases run with GetPathInDownloadDir(kInitialPath) as the inital
1475 const base::FilePath::CharType
* kInitialPath
=
1476 FILE_PATH_LITERAL("some_path/bar.txt");
1478 const DownloadTestCase kResumedTestCases
[] = {
1480 // 0: Automatic Safe: Initial path is ignored since the user has not been
1483 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
1484 "http://example.com/foo.txt", "text/plain",
1485 FILE_PATH_LITERAL(""),
1487 FILE_PATH_LITERAL("foo.txt"),
1488 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
1494 // 1: Save_As Safe: Initial path used.
1496 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
1497 "http://example.com/foo.txt", "text/plain",
1498 FILE_PATH_LITERAL(""),
1501 DownloadItem::TARGET_DISPOSITION_PROMPT
,
1507 // 2: Automatic Dangerous: Initial path is ignored since the user hasn't
1508 // been prompted before.
1510 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE
,
1511 "http://example.com/foo.crx", "",
1512 FILE_PATH_LITERAL(""),
1514 FILE_PATH_LITERAL("foo.crx"),
1515 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
1521 // 3: Forced Safe: Initial path is ignored due to the forced path.
1523 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
1524 "http://example.com/foo.txt", "",
1525 FILE_PATH_LITERAL("forced-foo.txt"),
1527 FILE_PATH_LITERAL("forced-foo.txt"),
1528 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
1534 // The test assumes that .crx files have a danger level of
1535 // ALLOW_ON_USER_GESTURE.
1536 ASSERT_EQ(download_util::ALLOW_ON_USER_GESTURE
,
1537 download_util::GetFileDangerLevel(
1538 base::FilePath(FILE_PATH_LITERAL("foo.crx"))));
1539 for (size_t i
= 0; i
< arraysize(kResumedTestCases
); ++i
) {
1540 SCOPED_TRACE(testing::Message() << "Running test case " << i
);
1541 const DownloadTestCase
& test_case
= kResumedTestCases
[i
];
1542 scoped_ptr
<content::MockDownloadItem
> item(
1543 CreateActiveDownloadItem(i
, test_case
));
1544 base::FilePath expected_path
=
1545 GetPathInDownloadDir(test_case
.expected_local_path
);
1546 ON_CALL(*item
.get(), GetLastReason())
1547 .WillByDefault(Return(
1548 content::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED
));
1549 // Extensions should be notified if a new path is being generated and there
1550 // is no forced path. In the test cases above, this is true for tests with
1551 // type == AUTOMATIC.
1552 EXPECT_CALL(*delegate(), NotifyExtensions(_
, _
, _
))
1553 .Times(test_case
.test_type
== AUTOMATIC
? 1 : 0);
1554 EXPECT_CALL(*delegate(), ReserveVirtualPath(_
, expected_path
, false, _
, _
));
1555 EXPECT_CALL(*delegate(), PromptUserForDownloadPath(_
, expected_path
, _
))
1557 EXPECT_CALL(*delegate(), DetermineLocalPath(_
, expected_path
, _
));
1558 EXPECT_CALL(*delegate(), CheckDownloadUrl(_
, expected_path
, _
));
1559 RunTestCase(test_case
, GetPathInDownloadDir(kInitialPath
), item
.get());
1563 // Test that a forced download doesn't prompt, even if the interrupt reason
1564 // suggests that the target path may not be suitable for downloads.
1565 TEST_F(DownloadTargetDeterminerTest
, TargetDeterminer_ResumedForcedDownload
) {
1566 const base::FilePath::CharType
* kInitialPath
=
1567 FILE_PATH_LITERAL("some_path/bar.txt");
1568 const DownloadTestCase kResumedForcedDownload
= {
1571 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
1572 "http://example.com/foo.txt", "",
1573 FILE_PATH_LITERAL("forced-foo.txt"),
1575 FILE_PATH_LITERAL("forced-foo.txt"),
1576 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
1581 const DownloadTestCase
& test_case
= kResumedForcedDownload
;
1582 base::FilePath expected_path
=
1583 GetPathInDownloadDir(test_case
.expected_local_path
);
1584 scoped_ptr
<content::MockDownloadItem
> item(
1585 CreateActiveDownloadItem(0, test_case
));
1586 ON_CALL(*item
.get(), GetLastReason())
1587 .WillByDefault(Return(content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE
));
1588 EXPECT_CALL(*delegate(), NotifyExtensions(_
, _
, _
))
1589 .Times(test_case
.test_type
== AUTOMATIC
? 1 : 0);
1590 EXPECT_CALL(*delegate(), ReserveVirtualPath(_
, expected_path
, false, _
, _
));
1591 EXPECT_CALL(*delegate(), PromptUserForDownloadPath(_
, _
, _
))
1593 EXPECT_CALL(*delegate(), DetermineLocalPath(_
, expected_path
, _
));
1594 EXPECT_CALL(*delegate(), CheckDownloadUrl(_
, expected_path
, _
));
1595 RunTestCase(test_case
, GetPathInDownloadDir(kInitialPath
), item
.get());
1598 // Prompting behavior for resumed downloads is based on the last interrupt
1599 // reason. If the reason indicates that the target path may not be suitable for
1600 // the download (ACCESS_DENIED, NO_SPACE, etc..), then the user should be
1601 // prompted, and not otherwise. These test cases result in prompting since the
1602 // error is set to NO_SPACE.
1603 TEST_F(DownloadTargetDeterminerTest
, TargetDeterminer_ResumedWithPrompt
) {
1604 // All test cases run with GetPathInDownloadDir(kInitialPath) as the inital
1606 const base::FilePath::CharType
* kInitialPath
=
1607 FILE_PATH_LITERAL("some_path/bar.txt");
1609 const DownloadTestCase kResumedTestCases
[] = {
1611 // 0: Automatic Safe
1613 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
1614 "http://example.com/foo.txt", "text/plain",
1615 FILE_PATH_LITERAL(""),
1617 FILE_PATH_LITERAL("foo.txt"),
1618 DownloadItem::TARGET_DISPOSITION_PROMPT
,
1626 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
1627 "http://example.com/foo.txt", "text/plain",
1628 FILE_PATH_LITERAL(""),
1631 DownloadItem::TARGET_DISPOSITION_PROMPT
,
1637 // 2: Automatic Dangerous
1639 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
1640 "http://example.com/foo.crx", "",
1641 FILE_PATH_LITERAL(""),
1643 FILE_PATH_LITERAL("foo.crx"),
1644 DownloadItem::TARGET_DISPOSITION_PROMPT
,
1650 // The test assumes that .xml files have a danger level of
1651 // ALLOW_ON_USER_GESTURE.
1652 ASSERT_EQ(download_util::ALLOW_ON_USER_GESTURE
,
1653 download_util::GetFileDangerLevel(
1654 base::FilePath(FILE_PATH_LITERAL("foo.crx"))));
1655 for (size_t i
= 0; i
< arraysize(kResumedTestCases
); ++i
) {
1656 SCOPED_TRACE(testing::Message() << "Running test case " << i
);
1657 download_prefs()->SetSaveFilePath(test_download_dir());
1658 const DownloadTestCase
& test_case
= kResumedTestCases
[i
];
1659 base::FilePath expected_path
=
1660 GetPathInDownloadDir(test_case
.expected_local_path
);
1661 scoped_ptr
<content::MockDownloadItem
> item(
1662 CreateActiveDownloadItem(i
, test_case
));
1663 ON_CALL(*item
.get(), GetLastReason())
1664 .WillByDefault(Return(
1665 content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE
));
1666 EXPECT_CALL(*delegate(), NotifyExtensions(_
, _
, _
))
1667 .Times(test_case
.test_type
== AUTOMATIC
? 1 : 0);
1668 EXPECT_CALL(*delegate(), ReserveVirtualPath(_
, expected_path
, false, _
, _
));
1669 EXPECT_CALL(*delegate(), PromptUserForDownloadPath(_
, expected_path
, _
));
1670 EXPECT_CALL(*delegate(), DetermineLocalPath(_
, expected_path
, _
));
1671 EXPECT_CALL(*delegate(), CheckDownloadUrl(_
, expected_path
, _
));
1672 RunTestCase(test_case
, GetPathInDownloadDir(kInitialPath
), item
.get());
1676 // Test intermediate filename generation for resumed downloads.
1677 TEST_F(DownloadTargetDeterminerTest
,
1678 TargetDeterminer_IntermediateNameForResumed
) {
1679 // All test cases run with GetPathInDownloadDir(kInitialPath) as the inital
1681 const base::FilePath::CharType kInitialPath
[] =
1682 FILE_PATH_LITERAL("some_path/bar.txt");
1684 struct IntermediateNameTestCase
{
1685 // General test case settings.
1686 DownloadTestCase general
;
1688 // Value of DownloadItem::GetFullPath() during test run, relative
1689 // to test download path.
1690 const base::FilePath::CharType
* initial_intermediate_path
;
1692 // Expected intermediate path relatvie to the test download path. An exact
1693 // match is performed if this string is non-empty. Ignored otherwise.
1694 const base::FilePath::CharType
* expected_intermediate_path
;
1695 } kIntermediateNameTestCases
[] = {
1698 // 0: Automatic Safe
1700 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
1701 "http://example.com/foo.txt", "text/plain",
1702 FILE_PATH_LITERAL(""),
1704 FILE_PATH_LITERAL("foo.txt"),
1705 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
1709 FILE_PATH_LITERAL("bar.txt.crdownload"),
1710 FILE_PATH_LITERAL("foo.txt.crdownload")
1717 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
1718 "http://example.com/foo.txt", "text/plain",
1719 FILE_PATH_LITERAL(""),
1722 DownloadItem::TARGET_DISPOSITION_PROMPT
,
1726 FILE_PATH_LITERAL("foo.txt.crdownload"),
1727 FILE_PATH_LITERAL("some_path/bar.txt.crdownload")
1732 // 2: Automatic Dangerous
1734 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE
,
1735 "http://example.com/foo.crx", "",
1736 FILE_PATH_LITERAL(""),
1738 FILE_PATH_LITERAL("foo.crx"),
1739 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
1743 FILE_PATH_LITERAL("Unconfirmed abcd.crdownload"),
1744 FILE_PATH_LITERAL("Unconfirmed abcd.crdownload")
1749 // 3: Automatic Dangerous
1751 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE
,
1752 "http://example.com/foo.crx", "",
1753 FILE_PATH_LITERAL(""),
1755 FILE_PATH_LITERAL("foo.crx"),
1756 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
1760 FILE_PATH_LITERAL("other_path/Unconfirmed abcd.crdownload"),
1761 // Rely on the EXPECT_UNCONFIRMED check in the general test settings. A
1762 // new intermediate path of the form "Unconfirmed <number>.crdownload"
1763 // should be generated for this case since the initial intermediate path
1764 // is in the wrong directory.
1765 FILE_PATH_LITERAL("")
1770 // 3: Forced Safe: Initial path is ignored due to the forced path.
1772 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
1773 "http://example.com/foo.txt", "",
1774 FILE_PATH_LITERAL("forced-foo.txt"),
1776 FILE_PATH_LITERAL("forced-foo.txt"),
1777 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
1781 FILE_PATH_LITERAL("forced-foo.txt"),
1782 FILE_PATH_LITERAL("forced-foo.txt")
1786 // The test assumes that .crx files have a danger level of
1787 // ALLOW_ON_USER_GESTURE.
1788 ASSERT_EQ(download_util::ALLOW_ON_USER_GESTURE
,
1789 download_util::GetFileDangerLevel(
1790 base::FilePath(FILE_PATH_LITERAL("foo.crx"))));
1792 for (size_t i
= 0; i
< arraysize(kIntermediateNameTestCases
); ++i
) {
1793 SCOPED_TRACE(testing::Message() << "Running test case " << i
);
1794 const IntermediateNameTestCase
& test_case
= kIntermediateNameTestCases
[i
];
1795 scoped_ptr
<content::MockDownloadItem
> item(
1796 CreateActiveDownloadItem(i
, test_case
.general
));
1798 ON_CALL(*item
.get(), GetLastReason())
1799 .WillByDefault(Return(
1800 content::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED
));
1801 ON_CALL(*item
.get(), GetFullPath())
1802 .WillByDefault(ReturnRefOfCopy(
1803 GetPathInDownloadDir(test_case
.initial_intermediate_path
)));
1804 ON_CALL(*item
.get(), GetDangerType())
1805 .WillByDefault(Return(test_case
.general
.expected_danger_type
));
1807 scoped_ptr
<DownloadTargetInfo
> target_info
=
1808 RunDownloadTargetDeterminer(GetPathInDownloadDir(kInitialPath
),
1810 VerifyDownloadTarget(test_case
.general
, target_info
.get());
1811 base::FilePath expected_intermediate_path
=
1812 GetPathInDownloadDir(test_case
.expected_intermediate_path
);
1813 if (!expected_intermediate_path
.empty())
1814 EXPECT_EQ(expected_intermediate_path
, target_info
->intermediate_path
);
1818 // Test MIME type determination based on the target filename.
1819 TEST_F(DownloadTargetDeterminerTest
,
1820 TargetDeterminer_MIMETypeDetermination
) {
1821 // All test cases run with GetPathInDownloadDir(kInitialPath) as the inital
1823 const base::FilePath::CharType kInitialPath
[] =
1824 FILE_PATH_LITERAL("some_path/bar.txt");
1826 struct MIMETypeTestCase
{
1827 // General test case settings.
1828 DownloadTestCase general
;
1830 // Expected MIME type for test case.
1831 const char* expected_mime_type
;
1832 } kMIMETypeTestCases
[] = {
1837 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
1838 "http://example.com/foo.png", "image/png",
1839 FILE_PATH_LITERAL(""),
1841 FILE_PATH_LITERAL("foo.png"),
1842 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
1850 // 1: Empty MIME type in response.
1852 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
1853 "http://example.com/foo.png", "",
1854 FILE_PATH_LITERAL(""),
1856 FILE_PATH_LITERAL("foo.png"),
1857 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
1867 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
1868 "http://example.com/foo.abc", "",
1869 FILE_PATH_LITERAL("foo.png"),
1871 FILE_PATH_LITERAL("foo.png"),
1872 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
1880 // 3: Unknown file type.
1882 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
1883 "http://example.com/foo.notarealext", "",
1884 FILE_PATH_LITERAL(""),
1886 FILE_PATH_LITERAL("foo.notarealext"),
1887 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
1895 // 4: Unknown file type.
1897 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
1898 "http://example.com/foo.notarealext", "image/png",
1899 FILE_PATH_LITERAL(""),
1901 FILE_PATH_LITERAL("foo.notarealext"),
1902 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
1910 ON_CALL(*delegate(), GetFileMimeType(
1911 GetPathInDownloadDir(FILE_PATH_LITERAL("foo.png")), _
))
1912 .WillByDefault(WithArg
<1>(
1913 ScheduleCallback("image/png")));
1915 for (size_t i
= 0; i
< arraysize(kMIMETypeTestCases
); ++i
) {
1916 SCOPED_TRACE(testing::Message() << "Running test case " << i
);
1917 const MIMETypeTestCase
& test_case
= kMIMETypeTestCases
[i
];
1918 scoped_ptr
<content::MockDownloadItem
> item(
1919 CreateActiveDownloadItem(i
, test_case
.general
));
1920 scoped_ptr
<DownloadTargetInfo
> target_info
=
1921 RunDownloadTargetDeterminer(GetPathInDownloadDir(kInitialPath
),
1923 EXPECT_EQ(test_case
.expected_mime_type
, target_info
->mime_type
);
1927 #if defined(ENABLE_PLUGINS)
1929 void DummyGetPluginsCallback(
1930 const base::Closure
& closure
,
1931 const std::vector
<content::WebPluginInfo
>& plugins
) {
1935 void ForceRefreshOfPlugins() {
1936 #if !defined(OS_WIN)
1937 // Prevent creation of a utility process for loading plugins. Doing so breaks
1938 // unit_tests since /proc/self/exe can't be run as a utility process.
1939 content::RenderProcessHost::SetRunRendererInProcess(true);
1941 base::RunLoop run_loop
;
1942 content::PluginService::GetInstance()->GetPlugins(
1943 base::Bind(&DummyGetPluginsCallback
, run_loop
.QuitClosure()));
1945 #if !defined(OS_WIN)
1946 content::RenderProcessHost::SetRunRendererInProcess(false);
1950 class MockPluginServiceFilter
: public content::PluginServiceFilter
{
1952 MOCK_METHOD1(MockPluginAvailable
, bool(const base::FilePath
&));
1954 virtual bool IsPluginAvailable(int render_process_id
,
1956 const void* context
,
1958 const GURL
& policy_url
,
1959 content::WebPluginInfo
* plugin
) override
{
1960 return MockPluginAvailable(plugin
->path
);
1963 virtual bool CanLoadPlugin(int render_process_id
,
1964 const base::FilePath
& path
) override
{
1969 class ScopedRegisterInternalPlugin
{
1971 ScopedRegisterInternalPlugin(content::PluginService
* plugin_service
,
1972 content::WebPluginInfo::PluginType type
,
1973 const base::FilePath
& path
,
1974 const char* mime_type
,
1975 const char* extension
)
1976 : plugin_service_(plugin_service
),
1977 plugin_path_(path
) {
1978 content::WebPluginMimeType
plugin_mime_type(mime_type
,
1981 content::WebPluginInfo
plugin_info(base::string16(),
1985 plugin_info
.mime_types
.push_back(plugin_mime_type
);
1986 plugin_info
.type
= type
;
1988 plugin_service
->RegisterInternalPlugin(plugin_info
, true);
1989 plugin_service
->RefreshPlugins();
1990 ForceRefreshOfPlugins();
1993 ~ScopedRegisterInternalPlugin() {
1994 plugin_service_
->UnregisterInternalPlugin(plugin_path_
);
1995 plugin_service_
->RefreshPlugins();
1996 ForceRefreshOfPlugins();
1999 const base::FilePath
& path() { return plugin_path_
; }
2002 content::PluginService
* plugin_service_
;
2003 base::FilePath plugin_path_
;
2006 // We use a slightly different test fixture for tests that touch plugins. SetUp
2007 // needs to disable plugin discovery and we need to use a
2008 // ShadowingAtExitManager to discard the tainted PluginService. Unfortunately,
2009 // PluginService carries global state.
2010 class DownloadTargetDeterminerTestWithPlugin
2011 : public DownloadTargetDeterminerTest
{
2013 DownloadTargetDeterminerTestWithPlugin()
2014 : old_plugin_service_filter_(NULL
) {}
2016 virtual void SetUp() override
{
2017 content::PluginService
* plugin_service
=
2018 content::PluginService::GetInstance();
2019 plugin_service
->Init();
2020 plugin_service
->DisablePluginsDiscoveryForTesting();
2021 old_plugin_service_filter_
= plugin_service
->GetFilter();
2022 plugin_service
->SetFilter(&mock_plugin_filter_
);
2023 DownloadTargetDeterminerTest::SetUp();
2026 virtual void TearDown() override
{
2027 content::PluginService::GetInstance()->SetFilter(
2028 old_plugin_service_filter_
);
2029 DownloadTargetDeterminerTest::TearDown();
2033 content::PluginServiceFilter
* old_plugin_service_filter_
;
2034 testing::StrictMock
<MockPluginServiceFilter
> mock_plugin_filter_
;
2035 // The ShadowingAtExitManager destroys the tainted PluginService instance.
2036 base::ShadowingAtExitManager at_exit_manager_
;
2039 // Check if secure handling of filetypes is determined correctly for PPAPI
2041 TEST_F(DownloadTargetDeterminerTestWithPlugin
,
2042 TargetDeterminer_CheckForSecureHandling_PPAPI
) {
2043 // All test cases run with GetPathInDownloadDir(kInitialPath) as the inital
2045 const base::FilePath::CharType kInitialPath
[] =
2046 FILE_PATH_LITERAL("some_path/bar.txt");
2047 const char kTestMIMEType
[] = "application/x-example-should-not-exist";
2049 DownloadTestCase kSecureHandlingTestCase
= {
2051 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
2052 "http://example.com/foo.fakeext", "",
2053 FILE_PATH_LITERAL(""),
2055 FILE_PATH_LITERAL("foo.fakeext"),
2056 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
2061 content::PluginService
* plugin_service
=
2062 content::PluginService::GetInstance();
2064 // Verify our test assumptions.
2066 ForceRefreshOfPlugins();
2067 std::vector
<content::WebPluginInfo
> info
;
2068 ASSERT_FALSE(plugin_service
->GetPluginInfoArray(
2069 GURL(), kTestMIMEType
, false, &info
, NULL
));
2070 ASSERT_EQ(0u, info
.size())
2071 << "Name: " << info
[0].name
<< ", Path: " << info
[0].path
.value();
2074 ON_CALL(*delegate(), GetFileMimeType(
2075 GetPathInDownloadDir(FILE_PATH_LITERAL("foo.fakeext")), _
))
2076 .WillByDefault(WithArg
<1>(
2077 ScheduleCallback(kTestMIMEType
)));
2078 scoped_ptr
<content::MockDownloadItem
> item(
2079 CreateActiveDownloadItem(1, kSecureHandlingTestCase
));
2080 scoped_ptr
<DownloadTargetInfo
> target_info
=
2081 RunDownloadTargetDeterminer(GetPathInDownloadDir(kInitialPath
),
2083 EXPECT_FALSE(target_info
->is_filetype_handled_safely
);
2085 // Register a PPAPI plugin. This should count as handling the filetype
2087 ScopedRegisterInternalPlugin
ppapi_plugin(
2089 content::WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS
,
2090 test_download_dir().AppendASCII("ppapi"),
2093 EXPECT_CALL(mock_plugin_filter_
, MockPluginAvailable(ppapi_plugin
.path()))
2094 .WillRepeatedly(Return(true));
2096 target_info
= RunDownloadTargetDeterminer(
2097 GetPathInDownloadDir(kInitialPath
), item
.get());
2098 EXPECT_TRUE(target_info
->is_filetype_handled_safely
);
2100 // Try disabling the plugin. Handling should no longer be considered secure.
2101 EXPECT_CALL(mock_plugin_filter_
, MockPluginAvailable(ppapi_plugin
.path()))
2102 .WillRepeatedly(Return(false));
2103 target_info
= RunDownloadTargetDeterminer(
2104 GetPathInDownloadDir(kInitialPath
), item
.get());
2105 EXPECT_FALSE(target_info
->is_filetype_handled_safely
);
2107 // Now register an unsandboxed PPAPI plug-in. This plugin should not be
2108 // considered secure.
2109 ScopedRegisterInternalPlugin
ppapi_unsandboxed_plugin(
2111 content::WebPluginInfo::PLUGIN_TYPE_PEPPER_UNSANDBOXED
,
2112 test_download_dir().AppendASCII("ppapi-nosandbox"),
2115 EXPECT_CALL(mock_plugin_filter_
,
2116 MockPluginAvailable(ppapi_unsandboxed_plugin
.path()))
2117 .WillRepeatedly(Return(true));
2119 target_info
= RunDownloadTargetDeterminer(
2120 GetPathInDownloadDir(kInitialPath
), item
.get());
2121 EXPECT_FALSE(target_info
->is_filetype_handled_safely
);
2124 // Check if secure handling of filetypes is determined correctly for NPAPI
2126 TEST_F(DownloadTargetDeterminerTestWithPlugin
,
2127 TargetDeterminer_CheckForSecureHandling_NPAPI
) {
2128 // All test cases run with GetPathInDownloadDir(kInitialPath) as the inital
2130 const base::FilePath::CharType kInitialPath
[] =
2131 FILE_PATH_LITERAL("some_path/bar.txt");
2132 const char kTestMIMEType
[] = "application/x-example-should-not-exist";
2134 DownloadTestCase kSecureHandlingTestCase
= {
2136 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
2137 "http://example.com/foo.fakeext", "",
2138 FILE_PATH_LITERAL(""),
2140 FILE_PATH_LITERAL("foo.fakeext"),
2141 DownloadItem::TARGET_DISPOSITION_OVERWRITE
,
2146 content::PluginService
* plugin_service
=
2147 content::PluginService::GetInstance();
2149 // Can't run this test if NPAPI isn't supported.
2150 if (!plugin_service
->NPAPIPluginsSupported())
2153 // Verify our test assumptions.
2155 ForceRefreshOfPlugins();
2156 std::vector
<content::WebPluginInfo
> info
;
2157 ASSERT_FALSE(plugin_service
->GetPluginInfoArray(
2158 GURL(), kTestMIMEType
, false, &info
, NULL
));
2159 ASSERT_EQ(0u, info
.size())
2160 << "Name: " << info
[0].name
<< ", Path: " << info
[0].path
.value();
2163 ON_CALL(*delegate(), GetFileMimeType(
2164 GetPathInDownloadDir(FILE_PATH_LITERAL("foo.fakeext")), _
))
2165 .WillByDefault(WithArg
<1>(
2166 ScheduleCallback(kTestMIMEType
)));
2167 scoped_ptr
<content::MockDownloadItem
> item(
2168 CreateActiveDownloadItem(1, kSecureHandlingTestCase
));
2169 scoped_ptr
<DownloadTargetInfo
> target_info
=
2170 RunDownloadTargetDeterminer(GetPathInDownloadDir(kInitialPath
),
2172 EXPECT_FALSE(target_info
->is_filetype_handled_safely
);
2174 // Register a NPAPI plugin. This should not count as handling the filetype
2176 ScopedRegisterInternalPlugin
npapi_plugin(
2178 content::WebPluginInfo::PLUGIN_TYPE_NPAPI
,
2179 test_download_dir().AppendASCII("npapi"),
2182 EXPECT_CALL(mock_plugin_filter_
, MockPluginAvailable(npapi_plugin
.path()))
2183 .WillRepeatedly(Return(true));
2185 target_info
= RunDownloadTargetDeterminer(
2186 GetPathInDownloadDir(kInitialPath
), item
.get());
2187 EXPECT_FALSE(target_info
->is_filetype_handled_safely
);
2189 #endif // defined(ENABLE_PLUGINS)