Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(174)

Side by Side Diff: chrome/browser/download/download_target_determiner.cc

Issue 12850002: Move download filename determintion into a separate class. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Add comments Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/download/download_target_determiner.h"
6
7 #include "base/prefs/pref_service.h"
8 #include "base/rand_util.h"
9 #include "base/stringprintf.h"
10 #include "base/time.h"
11 #include "chrome/browser/download/chrome_download_manager_delegate.h"
12 #include "chrome/browser/download/download_crx_util.h"
13 #include "chrome/browser/download/download_extensions.h"
14 #include "chrome/browser/download/download_prefs.h"
15 #include "chrome/browser/download/download_util.h"
16 #include "chrome/browser/extensions/api/downloads/downloads_api.h"
17 #include "chrome/browser/extensions/webstore_installer.h"
18 #include "chrome/browser/history/history_service.h"
19 #include "chrome/browser/history/history_service_factory.h"
20 #include "chrome/browser/profiles/profile.h"
21 #include "chrome/browser/safe_browsing/download_protection_service.h"
22 #include "chrome/common/extensions/feature_switch.h"
23 #include "chrome/common/pref_names.h"
24 #include "content/public/browser/browser_context.h"
25 #include "content/public/browser/browser_thread.h"
26 #include "grit/generated_resources.h"
27 #include "net/base/net_util.h"
28 #include "ui/base/l10n/l10n_util.h"
29
30 #if defined(OS_CHROMEOS)
31 #include "chrome/browser/chromeos/drive/drive_download_handler.h"
32 #include "chrome/browser/chromeos/drive/drive_file_system_util.h"
33 #endif
34
35 using content::BrowserThread;
36 using content::DownloadItem;
37 using safe_browsing::DownloadProtectionService;
38
39 namespace {
40
41 // Condenses the results from HistoryService::GetVisibleVisitCountToHost() to a
42 // single bool. A host is considered visited before if prior visible vists were
43 // found in history and the first such visit was earlier than the most recent
44 // midnight.
45 void VisitCountsToVisitedBefore(
46 const base::Callback<void(bool)>& callback,
47 HistoryService::Handle unused_handle,
48 bool found_visits,
49 int count,
50 base::Time first_visit) {
51 callback.Run(
52 found_visits && count > 0 &&
53 (first_visit.LocalMidnight() < base::Time::Now().LocalMidnight()));
54 }
55
56 } // namespace
57
58 DownloadTargetDeterminerDelegate::~DownloadTargetDeterminerDelegate() {
59 }
60
61 DownloadTargetDeterminer::DownloadTargetDeterminer(
62 DownloadItem* download,
63 DownloadPrefs* download_prefs,
64 const base::FilePath& last_selected_directory,
65 DownloadTargetDeterminerDelegate* delegate,
66 const CompletionCallback& callback)
67 : next_state_(STATE_GENERATE_TARGET_PATH),
68 should_prompt_(false),
69 should_overwrite_(!download->GetForcedFilePath().empty()),
70 danger_type_(download->GetDangerType()),
71 download_(download),
72 download_prefs_(download_prefs),
73 delegate_(delegate),
74 last_selected_directory_(last_selected_directory),
75 completion_callback_(callback),
76 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
77 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
78 DCHECK(download_);
79 DCHECK(delegate);
80 download_->AddObserver(this);
81
82 DoLoop();
83 }
84
85 DownloadTargetDeterminer::~DownloadTargetDeterminer() {
86 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
87 DCHECK(download_);
88 DCHECK(completion_callback_.is_null());
89 download_->RemoveObserver(this);
90 }
91
92 void DownloadTargetDeterminer::DoLoop() {
93 Result result = CONTINUE;
94
95 do {
96 switch (next_state_) {
97 case STATE_GENERATE_TARGET_PATH:
98 result = DoGenerateTargetPath();
99 break;
100 case STATE_NOTIFY_EXTENSIONS:
101 result = DoNotifyExtensions();
102 break;
103 case STATE_RESERVE_VIRTUAL_PATH:
104 result = DoReserveVirtualPath();
105 break;
106 case STATE_PROMPT_USER_FOR_DOWNLOAD_PATH:
107 result = DoPromptUserForDownloadPath();
108 break;
109 case STATE_DETERMINE_LOCAL_PATH:
110 result = DoDetermineLocalPath();
111 break;
112 case STATE_CHECK_DOWNLOAD_URL:
113 result = DoCheckDownloadUrl();
114 break;
115 case STATE_DETERMINE_DANGER_TYPE:
116 result = DoDetermineDangerType();
117 break;
118 case STATE_DETERMINE_INTERMEDIATE_PATH:
119 result = DoDetermineIntermediatePath();
120 break;
121 case STATE_CHECK_VISITED_REFERRER_BEFORE:
122 result = DoCheckVisitedReferrerBefore();
123 break;
124 case STATE_NONE:
125 NOTREACHED();
126 break;
127 }
128 } while (result == CONTINUE && next_state_ != STATE_NONE);
129
130 // Note that if a callback completes synchronously, the handler can still
131 // return PENDING. In this case, an inner DoLoop() may complete the target
132 // determination and delete |this|.
133 if (result == COMPLETE)
134 ScheduleCallbackAndDeleteSelf();
135 }
136
137 DownloadTargetDeterminer::Result
138 DownloadTargetDeterminer::DoGenerateTargetPath() {
139 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
140 DCHECK(virtual_path_.empty());
141 DCHECK(local_path_.empty());
142 bool is_forced_path = !download_->GetForcedFilePath().empty();
143 base::FilePath suggested_path;
144
145 next_state_ = STATE_NOTIFY_EXTENSIONS;
146
147 // If we don't have a forced path, we should construct a path for the
148 // download. Forced paths are only specified for programmatic downloads
149 // (WebStore, Drag&Drop).
150 if (!is_forced_path) {
151 std::string default_filename(
152 l10n_util::GetStringUTF8(IDS_DEFAULT_DOWNLOAD_FILENAME));
153 base::FilePath generated_filename = net::GenerateFileName(
154 download_->GetURL(),
155 download_->GetContentDisposition(),
156 GetProfile()->GetPrefs()->GetString(prefs::kDefaultCharset),
157 download_->GetSuggestedFilename(),
158 download_->GetMimeType(),
159 default_filename);
160 should_prompt_ = ShouldPromptForDownload(generated_filename);
161 base::FilePath target_directory;
162 if (should_prompt_ && !last_selected_directory_.empty()) {
163 DCHECK(!download_prefs_->IsDownloadPathManaged());
164 // If the user is going to be prompted and the user has been prompted
165 // before, then always prefer the last directory that the user selected.
166 target_directory = last_selected_directory_;
167 } else {
168 target_directory = download_prefs_->DownloadPath();
169 }
170 suggested_path = target_directory.Append(generated_filename);
171 } else {
172 DCHECK(!should_prompt_);
173 suggested_path = download_->GetForcedFilePath();
174 }
175 DCHECK(suggested_path.IsAbsolute());
176
177 // Treat the suggested_path as a virtual path. We will eventually determine
178 // whether this is a local path and if not, figure out a local path.
179 virtual_path_ = suggested_path;
180 DVLOG(20) << "Generated virtual path: " << virtual_path_.AsUTF8Unsafe();
181
182 // If the download is DOA, don't bother going any further. This would be the
183 // case for a download that failed to initialize (e.g. the initial temporary
184 // file couldn't be created because both the downloads directory and the
185 // temporary directory are unwriteable).
186 if (!download_->IsInProgress())
187 return COMPLETE;
Randy Smith (Not in Mondays) 2013/04/09 19:32:17 What's the logic for having this only here? This
asanka 2013/04/16 20:34:01 This early return is there so that a download that
Randy Smith (Not in Mondays) 2013/04/26 19:05:46 Makes sense. I don't find the comment clear for t
188 return CONTINUE;
189 }
190
191 DownloadTargetDeterminer::Result
192 DownloadTargetDeterminer::DoNotifyExtensions() {
193 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
194 DCHECK(!virtual_path_.empty());
195 ExtensionDownloadsEventRouter* router = delegate_->GetExtensionEventRouter();
196
197 next_state_ = STATE_RESERVE_VIRTUAL_PATH;
198
199 // If the target path is forced or if we don't have an extensions event
200 // router, then proceed with the original path.
201 if (!download_->GetForcedFilePath().empty() || !router)
202 return CONTINUE;
203
204 base::Closure original_path_callback =
205 base::Bind(&DownloadTargetDeterminer::NotifyExtensionsDone,
206 weak_ptr_factory_.GetWeakPtr(), base::FilePath(), false);
207 ExtensionDownloadsEventRouter::FilenameChangedCallback override_callback =
208 base::Bind(&DownloadTargetDeterminer::NotifyExtensionsDone,
209 weak_ptr_factory_.GetWeakPtr());
210 router->OnDeterminingFilename(download_, virtual_path_.BaseName(),
211 original_path_callback,
212 override_callback);
213 return PENDING;
214 }
215
216 void DownloadTargetDeterminer::NotifyExtensionsDone(
217 const base::FilePath& suggested_path,
218 bool should_overwrite) {
219 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
220 DVLOG(20) << "Extension suggested path: " << suggested_path.AsUTF8Unsafe();
221
222 if (!suggested_path.empty()) {
223 // TODO(asanka, benjhayden): The suggested path may contain path fragments.
224 // We need to validate each component individually. http://crbug.com/181332.
225
226 // If an extension overrides the filename, then the target directory will be
227 // forced to download_prefs_->DownloadPath() since extensions cannot place
228 // downloaded files anywhere except there. This prevents subdirectories from
229 // accumulating: if an extension is allowed to say that a file should go in
230 // last_download_path/music/foo.mp3, then last_download_path will accumulate
231 // the subdirectory /music/ so that the next download may end up in
232 // Downloads/music/music/music/bar.mp3.
233 base::FilePath new_path(download_prefs_->DownloadPath().Append(
234 suggested_path).NormalizePathSeparators());
235 // Do not pass a mime type to GenerateSafeFileName so that it does not force
236 // the filename to have an extension if the (Chrome) extension does not
237 // suggest it.
238 net::GenerateSafeFileName(std::string(), false, &new_path);
239 virtual_path_ = new_path;
240
241 // If |is_forced_path| were true, then extensions would not have been
242 // consulted, so use |overwrite| instead of |is_forced_path|. This does NOT
243 // set DownloadItem::GetForcedFilePath()!
244 should_overwrite_ = should_overwrite;
245 }
246
247 DoLoop();
248 }
249
250 DownloadTargetDeterminer::Result
251 DownloadTargetDeterminer::DoReserveVirtualPath() {
Randy Smith (Not in Mondays) 2013/04/09 19:32:17 What are your conceptual thoughts about reserving
asanka 2013/04/16 20:34:01 Reservation is supposed the check ...: - Whether t
252 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
253 DCHECK(!virtual_path_.empty());
254
255 next_state_ = STATE_PROMPT_USER_FOR_DOWNLOAD_PATH;
256
257 delegate_->ReserveVirtualPath(
258 download_, virtual_path_, !should_overwrite_,
259 base::Bind(&DownloadTargetDeterminer::ReserveVirtualPathDone,
260 weak_ptr_factory_.GetWeakPtr()));
261 return PENDING;
262 }
263
264 void DownloadTargetDeterminer::ReserveVirtualPathDone(
265 const base::FilePath& path, bool verified) {
266 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
267 DVLOG(20) << "Reserved path: " << path.AsUTF8Unsafe()
268 << " Verified:" << verified;
269 should_prompt_ = (should_prompt_ || !verified);
270 if (verified)
271 virtual_path_ = path;
272 DoLoop();
273 }
274
275 DownloadTargetDeterminer::Result
276 DownloadTargetDeterminer::DoPromptUserForDownloadPath() {
277 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
278 DCHECK(!virtual_path_.empty());
279
280 // We also prompt if the download path couldn't be verified.
Randy Smith (Not in Mondays) 2013/04/09 19:32:17 I was a bit confused by this (I thought it might b
asanka 2013/04/16 20:34:01 Removed the comment. It was stale.
281 if (should_prompt_) {
282 // If we are prompting, then delegate_->PromptUserForDownloadPathDone()
283 // returns both a local and virtual path, so we don't need to determine a
284 // local path in that case.
285 next_state_ = STATE_CHECK_DOWNLOAD_URL;
286 delegate_->PromptUserForDownloadPath(
287 download_,
288 virtual_path_,
289 base::Bind(&DownloadTargetDeterminer::PromptUserForDownloadPathDone,
290 weak_ptr_factory_.GetWeakPtr()));
291 return PENDING;
292 }
293
294 next_state_ = STATE_DETERMINE_LOCAL_PATH;
295 return CONTINUE;
296 }
297
298 void DownloadTargetDeterminer::PromptUserForDownloadPathDone(
299 const base::FilePath& virtual_path,
300 const base::FilePath& local_path) {
301 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
302 DVLOG(20) << "User selected paths (virtual):" << virtual_path.AsUTF8Unsafe()
303 << " (local):" << local_path.AsUTF8Unsafe();
304 if (virtual_path.empty()) {
305 CancelOnFailureAndDeleteSelf();
306 return;
307 }
308 virtual_path_ = virtual_path;
309 local_path_ = local_path;
310
311 DCHECK_EQ(STATE_CHECK_DOWNLOAD_URL, next_state_);
312 DoLoop();
313 }
314
315 DownloadTargetDeterminer::Result
316 DownloadTargetDeterminer::DoDetermineLocalPath() {
317 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
318 DCHECK(!virtual_path_.empty());
319 DCHECK(local_path_.empty());
320
321 next_state_ = STATE_CHECK_DOWNLOAD_URL;
322
323 delegate_->DetermineLocalPath(
324 download_,
325 virtual_path_,
326 base::Bind(&DownloadTargetDeterminer::DetermineLocalPathDone,
327 weak_ptr_factory_.GetWeakPtr()));
328 return PENDING;
329 }
330
331 void DownloadTargetDeterminer::DetermineLocalPathDone(
332 const base::FilePath& local_path) {
333 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
334 DVLOG(20) << "Local path: " << local_path.AsUTF8Unsafe();
335 local_path_ = local_path;
336 if (local_path_.empty()) {
337 // Path subsitution failed.
338 CancelOnFailureAndDeleteSelf();
339 return;
340 }
341 DoLoop();
342 }
343
344 DownloadTargetDeterminer::Result
345 DownloadTargetDeterminer::DoCheckDownloadUrl() {
346 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
347
348 next_state_ = STATE_DETERMINE_DANGER_TYPE;
349
350 #if defined(FULL_SAFE_BROWSING)
Randy Smith (Not in Mondays) 2013/04/09 19:32:17 Given that we have to have the ifdef anyway, I won
asanka 2013/04/16 20:34:01 Discussed elsewhere.
351 safe_browsing::DownloadProtectionService* service =
352 delegate_->GetDownloadProtectionService();
353 if (service) {
354 VLOG(2) << __FUNCTION__ << "() Start SB URL check for download = "
355 << download_->DebugString(false);
356 service->CheckDownloadUrl(
357 *download_,
358 base::Bind(
359 &DownloadTargetDeterminer::CheckDownloadUrlDone,
360 weak_ptr_factory_.GetWeakPtr()));
361 return PENDING;
362 }
363 #endif
364 return CONTINUE;
365 }
366
367 void DownloadTargetDeterminer::CheckDownloadUrlDone(
368 DownloadProtectionService::DownloadCheckResult result) {
369 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
370 DVLOG(20) << "URL Check Result:" << result;
371 if (result != DownloadProtectionService::SAFE)
372 danger_type_ = content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL;
373 DoLoop();
374 }
375
376 DownloadTargetDeterminer::Result
377 DownloadTargetDeterminer::DoDetermineDangerType() {
378 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
379 DCHECK(!virtual_path_.empty());
380
381 next_state_ = STATE_DETERMINE_INTERMEDIATE_PATH;
382
383 #if defined(FULL_SAFE_BROWSING)
384 // If the download hasn't already been marked dangerous (could be
385 // DANGEROUS_URL), check if it is a dangerous file.
386 if (danger_type_ == content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS) {
387 // If this type of files is handled by the enhanced SafeBrowsing download
388 // protection, mark it as potentially dangerous content until we are done
389 // with scanning it.
390 safe_browsing::DownloadProtectionService* service =
391 delegate_->GetDownloadProtectionService();
392 if (service && service->IsSupportedDownload(*download_, virtual_path_)) {
393 // TODO(noelutz): if the user changes the extension name in the UI to
394 // something like .exe SafeBrowsing will currently *not* check if the
395 // download is malicious.
396 danger_type_ = content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT;
397 }
398 } else {
399 DCHECK_EQ(content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL, danger_type_);
400 }
401 #endif
402
403 if (danger_type_ == content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS &&
404 !should_prompt_ &&
405 download_->GetForcedFilePath().empty()) {
406 next_state_ = STATE_CHECK_VISITED_REFERRER_BEFORE;
407 }
408 return CONTINUE;
409 }
410
411 DownloadTargetDeterminer::Result
412 DownloadTargetDeterminer::DoCheckVisitedReferrerBefore() {
413 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
414
415 next_state_ = STATE_DETERMINE_INTERMEDIATE_PATH;
416
417 // HistoryServiceFactory redirects incognito profiles to on-record profiles.
418 HistoryService* history_service = HistoryServiceFactory::GetForProfile(
419 GetProfile(), Profile::EXPLICIT_ACCESS);
420
421 if (history_service && download_->GetReferrerUrl().is_valid()) {
422 history_service->GetVisibleVisitCountToHost(
423 download_->GetReferrerUrl(), &history_consumer_,
424 base::Bind(&VisitCountsToVisitedBefore, base::Bind(
425 &DownloadTargetDeterminer::CheckVisitedReferrerBeforeDone,
426 weak_ptr_factory_.GetWeakPtr())));
427 return PENDING;
428 }
429
430 // If the original profile doesn't have a HistoryService or the referrer url
431 // is invalid, then give up and assume the referrer has not been visited
432 // before. There's no history for on-record profiles in unit_tests, for
433 // example.
434 if (IsDangerousFile(false))
Randy Smith (Not in Mondays) 2013/04/09 19:32:17 I'm not clear it's worth it, but you could refacto
asanka 2013/04/16 20:34:01 I decided to only ping the history thread if (!IsD
435 danger_type_ = content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE;
436 return CONTINUE;
437 }
438
439 void DownloadTargetDeterminer::CheckVisitedReferrerBeforeDone(
440 bool visited_referrer_before) {
441 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
442 if (IsDangerousFile(visited_referrer_before))
443 danger_type_ = content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE;
444 DoLoop();
445 }
446
447 DownloadTargetDeterminer::Result
448 DownloadTargetDeterminer::DoDetermineIntermediatePath() {
449 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
450 DCHECK(!virtual_path_.empty());
451 DCHECK(!local_path_.empty());
452 DCHECK(intermediate_path_.empty());
453
454 next_state_ = STATE_NONE;
455
456 if (virtual_path_.BaseName() != local_path_.BaseName() ||
457 (danger_type_ == content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS &&
458 !download_->GetForcedFilePath().empty())) {
459 // If the actual target of the download is a virtual path, then the local
460 // path is considered to point to a temporary path. A separate intermediate
461 // path is unnecessary since the local path already serves that purpose.
462 //
463 // Also, if the download has a forced path and is safe, then just use the
464 // target path.
465 intermediate_path_ = local_path_;
466 } else if (danger_type_ == content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS) {
467 // If the download is not dangerous, just append .crdownload to the target
468 // path.
469 intermediate_path_ = download_util::GetCrDownloadPath(local_path_);
470 } else {
471 // If the download is potentially dangerous we create a filename of the form
472 // 'Unconfirmed <random>.crdownload'.
473 base::FilePath::StringType file_name;
474 base::FilePath dir = local_path_.DirName();
475 #if defined(OS_WIN)
476 string16 unconfirmed_prefix =
477 l10n_util::GetStringUTF16(IDS_DOWNLOAD_UNCONFIRMED_PREFIX);
478 #else
479 std::string unconfirmed_prefix =
480 l10n_util::GetStringUTF8(IDS_DOWNLOAD_UNCONFIRMED_PREFIX);
481 #endif
482 base::SStringPrintf(
483 &file_name,
484 unconfirmed_prefix.append(
485 FILE_PATH_LITERAL(" %d.crdownload")).c_str(),
486 base::RandInt(0, 1000000));
487 intermediate_path_ = dir.Append(file_name);
488 }
489
490 return COMPLETE;
491 }
492
493 void DownloadTargetDeterminer::ScheduleCallbackAndDeleteSelf() {
494 DCHECK(download_);
495 DVLOG(20) << "Scheduling callback. Virtual:" << virtual_path_.AsUTF8Unsafe()
496 << " Local:" << local_path_.AsUTF8Unsafe()
497 << " Intermediate:" << intermediate_path_.AsUTF8Unsafe()
498 << " Should prompt:" << should_prompt_
499 << " Danger type:" << danger_type_;
500 MessageLoop::current()->PostTask(
501 FROM_HERE,
502 base::Bind(completion_callback_,
503 virtual_path_,
504 local_path_,
505 intermediate_path_,
506 (should_prompt_ ? DownloadItem::TARGET_DISPOSITION_PROMPT :
507 DownloadItem::TARGET_DISPOSITION_OVERWRITE),
508 danger_type_));
509 completion_callback_.Reset();
510 delete this;
511 }
512
513 void DownloadTargetDeterminer::CancelOnFailureAndDeleteSelf() {
514 // Path substitution failed.
515 virtual_path_.clear();
516 local_path_.clear();
517 intermediate_path_.clear();
518 ScheduleCallbackAndDeleteSelf();
519 }
520
521 Profile* DownloadTargetDeterminer::GetProfile() {
522 DCHECK(download_->GetBrowserContext());
523 return Profile::FromBrowserContext(download_->GetBrowserContext());
524 }
525
526 bool DownloadTargetDeterminer::ShouldPromptForDownload(
527 const base::FilePath& filename) {
528 // If the download path is forced, don't prompt.
529 if (!download_->GetForcedFilePath().empty()) {
530 // 'Save As' downloads shouldn't have a forced path.
531 DCHECK_NE(DownloadItem::TARGET_DISPOSITION_PROMPT,
532 download_->GetTargetDisposition());
533 return false;
534 }
535
536 // Don't ask where to save if the download path is managed. Even if the user
537 // wanted to be prompted for "all" downloads, or if this was a 'Save As'
538 // download.
539 if (download_prefs_->IsDownloadPathManaged())
540 return false;
541
542 // Prompt if this is a 'Save As' download.
543 if (download_->GetTargetDisposition() ==
544 DownloadItem::TARGET_DISPOSITION_PROMPT)
545 return true;
546
547 // Check if the user has the "Always prompt for download location" preference
548 // set. If so we prompt for most downloads except for the following scenarios:
549 // 1) Extension installation. Note that we only care here about the case where
550 // an extension is installed, not when one is downloaded with "save as...".
551 // 2) Filetypes marked "always open." If the user just wants this file opened,
552 // don't bother asking where to keep it.
553 if (download_prefs_->PromptForDownload() &&
554 !download_crx_util::IsExtensionDownload(*download_) &&
555 !extensions::Extension::IsExtension(filename) &&
556 !download_prefs_->IsAutoOpenEnabledBasedOnExtension(filename))
557 return true;
558
559 // Otherwise, don't prompt.
560 return false;
561 }
562
563 bool DownloadTargetDeterminer::IsDangerousFile(bool visited_referrer_before) {
564 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
565 const bool is_extension_download =
566 download_crx_util::IsExtensionDownload(*download_);
567
568 // User-initiated extension downloads from pref-whitelisted sources are not
569 // considered dangerous.
570 if (download_->HasUserGesture() &&
571 is_extension_download &&
572 download_crx_util::OffStoreInstallAllowedByPrefs(
573 GetProfile(), *download_)) {
574 return false;
575 }
576
577 // Extensions that are not from the gallery are considered dangerous.
578 // When off-store install is disabled we skip this, since in this case, we
579 // will not offer to install the extension.
580 if (extensions::FeatureSwitch::easy_off_store_install()->IsEnabled() &&
581 is_extension_download &&
582 !extensions::WebstoreInstaller::GetAssociatedApproval(*download_)) {
583 return true;
584 }
585
586 // Anything the user has marked auto-open is OK if it's user-initiated.
587 if (download_prefs_->IsAutoOpenEnabledBasedOnExtension(virtual_path_) &&
588 download_->HasUserGesture())
589 return false;
590
591 switch (download_util::GetFileDangerLevel(virtual_path_.BaseName())) {
592 case download_util::NotDangerous:
593 return false;
594
595 case download_util::AllowOnUserGesture:
596 // "Allow on user gesture" is OK when we have a user gesture and the
597 // hosting page has been visited before today.
598 if (download_->GetTransitionType() &
599 content::PAGE_TRANSITION_FROM_ADDRESS_BAR) {
600 return false;
601 }
602 return !download_->HasUserGesture() || !visited_referrer_before;
603
604 case download_util::Dangerous:
605 return true;
606 }
607 NOTREACHED();
608 return false;
609 }
610
611 void DownloadTargetDeterminer::OnDownloadDestroyed(
612 DownloadItem* download) {
613 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
614 DCHECK_EQ(download_, download);
615 CancelOnFailureAndDeleteSelf();
616 }
617
618 // static
619 void DownloadTargetDeterminer::Start(
620 content::DownloadItem* download,
621 DownloadPrefs* download_prefs,
622 const base::FilePath& last_selected_directory,
623 DownloadTargetDeterminerDelegate* delegate,
624 const CompletionCallback& callback) {
625 // DownloadTargetDeterminer owns itself and will self destruct when the job is
626 // complete or the download item is destroyed. The callback is always invoked
627 // asynchronously.
628 new DownloadTargetDeterminer(download, download_prefs,
629 last_selected_directory, delegate, callback);
630 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698