OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/download/download_target_determiner.h" | 5 #include "chrome/browser/download/download_target_determiner.h" |
6 | 6 |
7 #include "base/prefs/pref_service.h" | 7 #include "base/prefs/pref_service.h" |
8 #include "base/rand_util.h" | 8 #include "base/rand_util.h" |
9 #include "base/strings/stringprintf.h" | 9 #include "base/strings/stringprintf.h" |
10 #include "base/time/time.h" | 10 #include "base/time/time.h" |
11 #include "chrome/browser/download/chrome_download_manager_delegate.h" | 11 #include "chrome/browser/download/chrome_download_manager_delegate.h" |
12 #include "chrome/browser/download/download_crx_util.h" | 12 #include "chrome/browser/download/download_crx_util.h" |
13 #include "chrome/browser/download/download_extensions.h" | 13 #include "chrome/browser/download/download_extensions.h" |
14 #include "chrome/browser/download/download_prefs.h" | 14 #include "chrome/browser/download/download_prefs.h" |
15 #include "chrome/browser/extensions/webstore_installer.h" | 15 #include "chrome/browser/extensions/webstore_installer.h" |
16 #include "chrome/browser/history/history_service.h" | 16 #include "chrome/browser/history/history_service.h" |
17 #include "chrome/browser/history/history_service_factory.h" | 17 #include "chrome/browser/history/history_service_factory.h" |
18 #include "chrome/browser/profiles/profile.h" | 18 #include "chrome/browser/profiles/profile.h" |
19 #include "chrome/common/extensions/feature_switch.h" | 19 #include "chrome/common/extensions/feature_switch.h" |
20 #include "chrome/common/pref_names.h" | 20 #include "chrome/common/pref_names.h" |
21 #include "content/public/browser/browser_context.h" | 21 #include "content/public/browser/browser_context.h" |
22 #include "content/public/browser/browser_thread.h" | 22 #include "content/public/browser/browser_thread.h" |
23 #include "content/public/browser/download_interrupt_reasons.h" | 23 #include "content/public/browser/download_interrupt_reasons.h" |
24 #include "extensions/common/constants.h" | 24 #include "extensions/common/constants.h" |
25 #include "grit/generated_resources.h" | 25 #include "grit/generated_resources.h" |
26 #include "net/base/mime_util.h" | |
26 #include "net/base/net_util.h" | 27 #include "net/base/net_util.h" |
27 #include "ui/base/l10n/l10n_util.h" | 28 #include "ui/base/l10n/l10n_util.h" |
28 | 29 |
30 #if defined(ENABLE_PLUGINS) | |
31 #include "chrome/browser/plugins/plugin_prefs.h" | |
32 #include "content/public/browser/plugin_service.h" | |
33 #include "content/public/common/webplugininfo.h" | |
34 #endif | |
35 | |
29 using content::BrowserThread; | 36 using content::BrowserThread; |
30 using content::DownloadItem; | 37 using content::DownloadItem; |
31 | 38 |
32 namespace { | 39 namespace { |
33 | 40 |
34 const base::FilePath::CharType kCrdownloadSuffix[] = | 41 const base::FilePath::CharType kCrdownloadSuffix[] = |
35 FILE_PATH_LITERAL(".crdownload"); | 42 FILE_PATH_LITERAL(".crdownload"); |
36 | 43 |
37 // Condenses the results from HistoryService::GetVisibleVisitCountToHost() to a | 44 // Condenses the results from HistoryService::GetVisibleVisitCountToHost() to a |
38 // single bool. A host is considered visited before if prior visible visits were | 45 // single bool. A host is considered visited before if prior visible visits were |
39 // found in history and the first such visit was earlier than the most recent | 46 // found in history and the first such visit was earlier than the most recent |
40 // midnight. | 47 // midnight. |
41 void VisitCountsToVisitedBefore( | 48 void VisitCountsToVisitedBefore( |
42 const base::Callback<void(bool)>& callback, | 49 const base::Callback<void(bool)>& callback, |
43 HistoryService::Handle unused_handle, | 50 HistoryService::Handle unused_handle, |
44 bool found_visits, | 51 bool found_visits, |
45 int count, | 52 int count, |
46 base::Time first_visit) { | 53 base::Time first_visit) { |
47 callback.Run( | 54 callback.Run( |
48 found_visits && count > 0 && | 55 found_visits && count > 0 && |
49 (first_visit.LocalMidnight() < base::Time::Now().LocalMidnight())); | 56 (first_visit.LocalMidnight() < base::Time::Now().LocalMidnight())); |
50 } | 57 } |
51 | 58 |
52 } // namespace | 59 } // namespace |
53 | 60 |
61 DownloadTargetInfo::DownloadTargetInfo() | |
62 : is_filetype_handled_securely(false) {} | |
63 | |
64 DownloadTargetInfo::~DownloadTargetInfo() {} | |
65 | |
54 DownloadTargetDeterminerDelegate::~DownloadTargetDeterminerDelegate() { | 66 DownloadTargetDeterminerDelegate::~DownloadTargetDeterminerDelegate() { |
55 } | 67 } |
56 | 68 |
57 DownloadTargetDeterminer::DownloadTargetDeterminer( | 69 DownloadTargetDeterminer::DownloadTargetDeterminer( |
58 DownloadItem* download, | 70 DownloadItem* download, |
59 const base::FilePath& initial_virtual_path, | 71 const base::FilePath& initial_virtual_path, |
60 DownloadPrefs* download_prefs, | 72 DownloadPrefs* download_prefs, |
61 DownloadTargetDeterminerDelegate* delegate, | 73 DownloadTargetDeterminerDelegate* delegate, |
62 const content::DownloadTargetCallback& callback) | 74 const CompletionCallback& callback) |
63 : next_state_(STATE_GENERATE_TARGET_PATH), | 75 : next_state_(STATE_GENERATE_TARGET_PATH), |
64 should_prompt_(false), | 76 should_prompt_(false), |
65 should_notify_extensions_(false), | 77 should_notify_extensions_(false), |
66 create_target_directory_(false), | 78 create_target_directory_(false), |
67 conflict_action_(DownloadPathReservationTracker::OVERWRITE), | 79 conflict_action_(DownloadPathReservationTracker::OVERWRITE), |
68 danger_type_(download->GetDangerType()), | 80 danger_type_(download->GetDangerType()), |
69 virtual_path_(initial_virtual_path), | 81 virtual_path_(initial_virtual_path), |
82 is_filetype_handled_securely_(false), | |
70 download_(download), | 83 download_(download), |
71 is_resumption_(download_->GetLastReason() != | 84 is_resumption_(download_->GetLastReason() != |
72 content::DOWNLOAD_INTERRUPT_REASON_NONE && | 85 content::DOWNLOAD_INTERRUPT_REASON_NONE && |
73 !initial_virtual_path.empty()), | 86 !initial_virtual_path.empty()), |
74 download_prefs_(download_prefs), | 87 download_prefs_(download_prefs), |
75 delegate_(delegate), | 88 delegate_(delegate), |
76 completion_callback_(callback), | 89 completion_callback_(callback), |
77 weak_ptr_factory_(this) { | 90 weak_ptr_factory_(this) { |
78 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 91 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
79 DCHECK(download_); | 92 DCHECK(download_); |
(...skipping 25 matching lines...) Expand all Loading... | |
105 break; | 118 break; |
106 case STATE_RESERVE_VIRTUAL_PATH: | 119 case STATE_RESERVE_VIRTUAL_PATH: |
107 result = DoReserveVirtualPath(); | 120 result = DoReserveVirtualPath(); |
108 break; | 121 break; |
109 case STATE_PROMPT_USER_FOR_DOWNLOAD_PATH: | 122 case STATE_PROMPT_USER_FOR_DOWNLOAD_PATH: |
110 result = DoPromptUserForDownloadPath(); | 123 result = DoPromptUserForDownloadPath(); |
111 break; | 124 break; |
112 case STATE_DETERMINE_LOCAL_PATH: | 125 case STATE_DETERMINE_LOCAL_PATH: |
113 result = DoDetermineLocalPath(); | 126 result = DoDetermineLocalPath(); |
114 break; | 127 break; |
128 case STATE_DETERMINE_MIME_TYPE: | |
129 result = DoDetermineMimeType(); | |
130 break; | |
131 case STATE_DETERMINE_IF_HANDLED_BY_BROWSER: | |
132 result = DoDetermineIfHandledByBrowser(); | |
133 break; | |
115 case STATE_CHECK_DOWNLOAD_URL: | 134 case STATE_CHECK_DOWNLOAD_URL: |
116 result = DoCheckDownloadUrl(); | 135 result = DoCheckDownloadUrl(); |
117 break; | 136 break; |
118 case STATE_DETERMINE_INTERMEDIATE_PATH: | 137 case STATE_DETERMINE_INTERMEDIATE_PATH: |
119 result = DoDetermineIntermediatePath(); | 138 result = DoDetermineIntermediatePath(); |
120 break; | 139 break; |
121 case STATE_CHECK_VISITED_REFERRER_BEFORE: | 140 case STATE_CHECK_VISITED_REFERRER_BEFORE: |
122 result = DoCheckVisitedReferrerBefore(); | 141 result = DoCheckVisitedReferrerBefore(); |
123 break; | 142 break; |
124 case STATE_NONE: | 143 case STATE_NONE: |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
298 download_prefs_->SetSaveFilePath(virtual_path_.DirName()); | 317 download_prefs_->SetSaveFilePath(virtual_path_.DirName()); |
299 DoLoop(); | 318 DoLoop(); |
300 } | 319 } |
301 | 320 |
302 DownloadTargetDeterminer::Result | 321 DownloadTargetDeterminer::Result |
303 DownloadTargetDeterminer::DoDetermineLocalPath() { | 322 DownloadTargetDeterminer::DoDetermineLocalPath() { |
304 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 323 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
305 DCHECK(!virtual_path_.empty()); | 324 DCHECK(!virtual_path_.empty()); |
306 DCHECK(local_path_.empty()); | 325 DCHECK(local_path_.empty()); |
307 | 326 |
308 next_state_ = STATE_CHECK_DOWNLOAD_URL; | 327 next_state_ = STATE_DETERMINE_MIME_TYPE; |
309 | 328 |
310 delegate_->DetermineLocalPath( | 329 delegate_->DetermineLocalPath( |
311 download_, | 330 download_, |
312 virtual_path_, | 331 virtual_path_, |
313 base::Bind(&DownloadTargetDeterminer::DetermineLocalPathDone, | 332 base::Bind(&DownloadTargetDeterminer::DetermineLocalPathDone, |
314 weak_ptr_factory_.GetWeakPtr())); | 333 weak_ptr_factory_.GetWeakPtr())); |
315 return QUIT_DOLOOP; | 334 return QUIT_DOLOOP; |
316 } | 335 } |
317 | 336 |
318 void DownloadTargetDeterminer::DetermineLocalPathDone( | 337 void DownloadTargetDeterminer::DetermineLocalPathDone( |
319 const base::FilePath& local_path) { | 338 const base::FilePath& local_path) { |
320 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 339 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
321 DVLOG(20) << "Local path: " << local_path.AsUTF8Unsafe(); | 340 DVLOG(20) << "Local path: " << local_path.AsUTF8Unsafe(); |
322 if (local_path.empty()) { | 341 if (local_path.empty()) { |
323 // Path subsitution failed. | 342 // Path subsitution failed. |
324 CancelOnFailureAndDeleteSelf(); | 343 CancelOnFailureAndDeleteSelf(); |
325 return; | 344 return; |
326 } | 345 } |
327 local_path_ = local_path; | 346 local_path_ = local_path; |
328 DoLoop(); | 347 DoLoop(); |
329 } | 348 } |
330 | 349 |
331 DownloadTargetDeterminer::Result | 350 DownloadTargetDeterminer::Result |
351 DownloadTargetDeterminer::DoDetermineMimeType() { | |
352 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
353 DCHECK(!virtual_path_.empty()); | |
354 DCHECK(!local_path_.empty()); | |
355 DCHECK(mime_type_.empty()); | |
356 | |
357 next_state_ = STATE_DETERMINE_IF_HANDLED_BY_BROWSER; | |
358 | |
359 if (virtual_path_ == local_path_) { | |
360 delegate_->GetFileMimeType( | |
361 local_path_, | |
362 base::Bind(&DownloadTargetDeterminer::DetermineMimeTypeDone, | |
363 weak_ptr_factory_.GetWeakPtr())); | |
364 return QUIT_DOLOOP; | |
365 } | |
366 return CONTINUE; | |
367 } | |
368 | |
369 void DownloadTargetDeterminer::DetermineMimeTypeDone( | |
370 const std::string& mime_type) { | |
371 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
372 DVLOG(20) << "MIME type: " << mime_type; | |
373 mime_type_ = mime_type; | |
374 DoLoop(); | |
375 } | |
376 | |
377 #if defined(ENABLE_PLUGINS) | |
378 // The code below is used by DoDetermineIfHandledByBrowser to determine if the | |
379 // file type is handled by a sandboxed plugin. | |
380 namespace { | |
381 | |
382 typedef std::vector<content::WebPluginInfo> PluginVector; | |
383 | |
384 // Returns true if there is a plugin in |plugins| that is sandboxed and enabled | |
385 // for |profile|. | |
386 bool IsSafePluginAvailableForProfile(scoped_ptr<PluginVector> plugins, | |
387 Profile* profile) { | |
388 using content::WebPluginInfo; | |
389 | |
390 if (plugins->size() == 0) | |
391 return false; | |
392 | |
393 scoped_refptr<PluginPrefs> plugin_prefs = PluginPrefs::GetForProfile(profile); | |
394 if (!plugin_prefs) | |
395 return false; | |
396 | |
397 for (PluginVector::iterator plugin = plugins->begin(); | |
398 plugin != plugins->end(); ++plugin) { | |
399 if (plugin_prefs->IsPluginEnabled(*plugin) && | |
400 (plugin->type == WebPluginInfo::PLUGIN_TYPE_PEPPER_IN_PROCESS || | |
401 plugin->type == WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS)) | |
402 return true; | |
403 } | |
404 return false; | |
405 } | |
406 | |
407 // Returns a callback that determines if a sandboxed plugin is available to | |
408 // handle |mime_type| for a specific profile. Must be called on the IO thread. | |
Randy Smith (Not in Mondays)
2013/11/04 22:57:47
nit: The second sentence can be ambiguously read a
asanka
2013/11/05 21:31:39
Done. Reworded to explicitly state thread restrict
| |
409 base::Callback<bool(Profile*)> GetSafePluginChecker( | |
410 const std::string& mime_type) { | |
411 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
412 DCHECK(!mime_type.empty()); | |
413 | |
414 scoped_ptr<PluginVector> plugins(new PluginVector); | |
415 content::PluginService* plugin_service = | |
416 content::PluginService::GetInstance(); | |
417 if (plugin_service) | |
418 plugin_service->GetPluginInfoArray( | |
419 GURL(), mime_type, false, plugins.get(), NULL); | |
420 return base::Bind(&IsSafePluginAvailableForProfile, base::Passed(&plugins)); | |
421 } | |
422 | |
423 } // namespace | |
424 #endif // ENABLE_PLUGINS | |
425 | |
426 DownloadTargetDeterminer::Result | |
427 DownloadTargetDeterminer::DoDetermineIfHandledByBrowser() { | |
428 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
429 DCHECK(!virtual_path_.empty()); | |
430 DCHECK(!local_path_.empty()); | |
431 DCHECK(!is_filetype_handled_securely_); | |
432 | |
433 next_state_ = STATE_CHECK_DOWNLOAD_URL; | |
434 | |
435 if (mime_type_.empty()) | |
436 return CONTINUE; | |
437 | |
438 if (net::IsSupportedMimeType(mime_type_)) { | |
439 is_filetype_handled_securely_ = true; | |
440 return CONTINUE; | |
441 } | |
442 | |
443 #if defined(ENABLE_PLUGINS) | |
444 BrowserThread::PostTaskAndReplyWithResult( | |
445 BrowserThread::IO, | |
446 FROM_HERE, | |
447 base::Bind(&GetSafePluginChecker, mime_type_), | |
448 base::Bind(&DownloadTargetDeterminer::DetermineIfHandledByBrowserDone, | |
Randy Smith (Not in Mondays)
2013/11/04 22:57:47
Just confirming: I read this code as using the mim
asanka
2013/11/05 21:31:39
The flow for file:// URLs is:
//net:
- MIME type
| |
449 weak_ptr_factory_.GetWeakPtr())); | |
450 return QUIT_DOLOOP; | |
451 #else | |
452 return CONTINUE; | |
453 #endif | |
454 } | |
455 | |
456 void DownloadTargetDeterminer::DetermineIfHandledByBrowserDone( | |
457 const base::Callback<bool(Profile*)>& callback) { | |
458 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
459 is_filetype_handled_securely_ = callback.Run(GetProfile()); | |
460 DVLOG(20) << "Is file type handled securely: " | |
461 << is_filetype_handled_securely_; | |
462 DoLoop(); | |
463 } | |
464 | |
465 DownloadTargetDeterminer::Result | |
332 DownloadTargetDeterminer::DoCheckDownloadUrl() { | 466 DownloadTargetDeterminer::DoCheckDownloadUrl() { |
333 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 467 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
334 DCHECK(!virtual_path_.empty()); | 468 DCHECK(!virtual_path_.empty()); |
335 next_state_ = STATE_CHECK_VISITED_REFERRER_BEFORE; | 469 next_state_ = STATE_CHECK_VISITED_REFERRER_BEFORE; |
336 delegate_->CheckDownloadUrl( | 470 delegate_->CheckDownloadUrl( |
337 download_, | 471 download_, |
338 virtual_path_, | 472 virtual_path_, |
339 base::Bind(&DownloadTargetDeterminer::CheckDownloadUrlDone, | 473 base::Bind(&DownloadTargetDeterminer::CheckDownloadUrlDone, |
340 weak_ptr_factory_.GetWeakPtr())); | 474 weak_ptr_factory_.GetWeakPtr())); |
341 return QUIT_DOLOOP; | 475 return QUIT_DOLOOP; |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
477 return COMPLETE; | 611 return COMPLETE; |
478 } | 612 } |
479 | 613 |
480 void DownloadTargetDeterminer::ScheduleCallbackAndDeleteSelf() { | 614 void DownloadTargetDeterminer::ScheduleCallbackAndDeleteSelf() { |
481 DCHECK(download_); | 615 DCHECK(download_); |
482 DVLOG(20) << "Scheduling callback. Virtual:" << virtual_path_.AsUTF8Unsafe() | 616 DVLOG(20) << "Scheduling callback. Virtual:" << virtual_path_.AsUTF8Unsafe() |
483 << " Local:" << local_path_.AsUTF8Unsafe() | 617 << " Local:" << local_path_.AsUTF8Unsafe() |
484 << " Intermediate:" << intermediate_path_.AsUTF8Unsafe() | 618 << " Intermediate:" << intermediate_path_.AsUTF8Unsafe() |
485 << " Should prompt:" << should_prompt_ | 619 << " Should prompt:" << should_prompt_ |
486 << " Danger type:" << danger_type_; | 620 << " Danger type:" << danger_type_; |
621 scoped_ptr<DownloadTargetInfo> target_info(new DownloadTargetInfo); | |
622 | |
623 target_info->target_path = local_path_; | |
624 target_info->target_disposition = | |
625 (HasPromptedForPath() || should_prompt_ | |
626 ? DownloadItem::TARGET_DISPOSITION_PROMPT | |
627 : DownloadItem::TARGET_DISPOSITION_OVERWRITE); | |
628 target_info->danger_type = danger_type_; | |
629 target_info->intermediate_path = intermediate_path_; | |
630 target_info->mime_type = mime_type_; | |
631 target_info->is_filetype_handled_securely = is_filetype_handled_securely_; | |
632 | |
487 base::MessageLoop::current()->PostTask( | 633 base::MessageLoop::current()->PostTask( |
488 FROM_HERE, | 634 FROM_HERE, base::Bind(completion_callback_, base::Passed(&target_info))); |
489 base::Bind(completion_callback_, | |
490 local_path_, | |
491 (HasPromptedForPath() || should_prompt_ | |
492 ? DownloadItem::TARGET_DISPOSITION_PROMPT | |
493 : DownloadItem::TARGET_DISPOSITION_OVERWRITE), | |
494 danger_type_, | |
495 intermediate_path_)); | |
496 completion_callback_.Reset(); | 635 completion_callback_.Reset(); |
497 delete this; | 636 delete this; |
498 } | 637 } |
499 | 638 |
500 void DownloadTargetDeterminer::CancelOnFailureAndDeleteSelf() { | 639 void DownloadTargetDeterminer::CancelOnFailureAndDeleteSelf() { |
501 // Path substitution failed. | 640 // Path substitution failed. |
502 virtual_path_.clear(); | 641 virtual_path_.clear(); |
503 local_path_.clear(); | 642 local_path_.clear(); |
504 intermediate_path_.clear(); | 643 intermediate_path_.clear(); |
505 ScheduleCallbackAndDeleteSelf(); | 644 ScheduleCallbackAndDeleteSelf(); |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
624 } | 763 } |
625 | 764 |
626 void DownloadTargetDeterminer::OnDownloadDestroyed( | 765 void DownloadTargetDeterminer::OnDownloadDestroyed( |
627 DownloadItem* download) { | 766 DownloadItem* download) { |
628 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 767 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
629 DCHECK_EQ(download_, download); | 768 DCHECK_EQ(download_, download); |
630 CancelOnFailureAndDeleteSelf(); | 769 CancelOnFailureAndDeleteSelf(); |
631 } | 770 } |
632 | 771 |
633 // static | 772 // static |
634 void DownloadTargetDeterminer::Start( | 773 void DownloadTargetDeterminer::Start(content::DownloadItem* download, |
635 content::DownloadItem* download, | 774 const base::FilePath& initial_virtual_path, |
636 const base::FilePath& initial_virtual_path, | 775 DownloadPrefs* download_prefs, |
637 DownloadPrefs* download_prefs, | 776 DownloadTargetDeterminerDelegate* delegate, |
638 DownloadTargetDeterminerDelegate* delegate, | 777 const CompletionCallback& callback) { |
639 const content::DownloadTargetCallback& callback) { | |
640 // DownloadTargetDeterminer owns itself and will self destruct when the job is | 778 // DownloadTargetDeterminer owns itself and will self destruct when the job is |
641 // complete or the download item is destroyed. The callback is always invoked | 779 // complete or the download item is destroyed. The callback is always invoked |
642 // asynchronously. | 780 // asynchronously. |
643 new DownloadTargetDeterminer(download, initial_virtual_path, download_prefs, | 781 new DownloadTargetDeterminer(download, initial_virtual_path, download_prefs, |
644 delegate, callback); | 782 delegate, callback); |
645 } | 783 } |
646 | 784 |
647 // static | 785 // static |
648 base::FilePath DownloadTargetDeterminer::GetCrDownloadPath( | 786 base::FilePath DownloadTargetDeterminer::GetCrDownloadPath( |
649 const base::FilePath& suggested_path) { | 787 const base::FilePath& suggested_path) { |
650 return base::FilePath(suggested_path.value() + kCrdownloadSuffix); | 788 return base::FilePath(suggested_path.value() + kCrdownloadSuffix); |
651 } | 789 } |
OLD | NEW |