| 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 <string> |
| 8 #include <vector> |
| 9 |
| 7 #include "base/location.h" | 10 #include "base/location.h" |
| 8 #include "base/rand_util.h" | 11 #include "base/rand_util.h" |
| 9 #include "base/single_thread_task_runner.h" | 12 #include "base/single_thread_task_runner.h" |
| 10 #include "base/strings/stringprintf.h" | 13 #include "base/strings/stringprintf.h" |
| 11 #include "base/threading/thread_task_runner_handle.h" | 14 #include "base/threading/thread_task_runner_handle.h" |
| 12 #include "base/time/time.h" | 15 #include "base/time/time.h" |
| 13 #include "build/build_config.h" | |
| 14 #include "chrome/browser/download/chrome_download_manager_delegate.h" | 16 #include "chrome/browser/download/chrome_download_manager_delegate.h" |
| 15 #include "chrome/browser/download/download_crx_util.h" | 17 #include "chrome/browser/download/download_crx_util.h" |
| 16 #include "chrome/browser/download/download_prefs.h" | 18 #include "chrome/browser/download/download_prefs.h" |
| 17 #include "chrome/browser/history/history_service_factory.h" | 19 #include "chrome/browser/history/history_service_factory.h" |
| 18 #include "chrome/browser/profiles/profile.h" | 20 #include "chrome/browser/profiles/profile.h" |
| 19 #include "chrome/common/pref_names.h" | 21 #include "chrome/common/pref_names.h" |
| 20 #include "chrome/common/safe_browsing/file_type_policies.h" | 22 #include "chrome/common/safe_browsing/file_type_policies.h" |
| 21 #include "chrome/grit/generated_resources.h" | 23 #include "chrome/grit/generated_resources.h" |
| 22 #include "components/history/core/browser/history_service.h" | 24 #include "components/history/core/browser/history_service.h" |
| 23 #include "components/mime_util/mime_util.h" | 25 #include "components/mime_util/mime_util.h" |
| (...skipping 10 matching lines...) Expand all Loading... |
| 34 #include "chrome/browser/extensions/webstore_installer.h" | 36 #include "chrome/browser/extensions/webstore_installer.h" |
| 35 #include "extensions/common/feature_switch.h" | 37 #include "extensions/common/feature_switch.h" |
| 36 #endif | 38 #endif |
| 37 | 39 |
| 38 #if defined(ENABLE_PLUGINS) | 40 #if defined(ENABLE_PLUGINS) |
| 39 #include "chrome/browser/plugins/plugin_prefs.h" | 41 #include "chrome/browser/plugins/plugin_prefs.h" |
| 40 #include "content/public/browser/plugin_service.h" | 42 #include "content/public/browser/plugin_service.h" |
| 41 #include "content/public/common/webplugininfo.h" | 43 #include "content/public/common/webplugininfo.h" |
| 42 #endif | 44 #endif |
| 43 | 45 |
| 44 #if defined(OS_ANDROID) | |
| 45 #include "chrome/browser/android/download/download_controller.h" | |
| 46 #include "chrome/browser/android/download/download_manager_service.h" | |
| 47 #endif | |
| 48 | |
| 49 #if defined(OS_WIN) | 46 #if defined(OS_WIN) |
| 50 #include "chrome/browser/ui/pdf/adobe_reader_info_win.h" | 47 #include "chrome/browser/ui/pdf/adobe_reader_info_win.h" |
| 51 #endif | 48 #endif |
| 52 | 49 |
| 53 using content::BrowserThread; | 50 using content::BrowserThread; |
| 54 using content::DownloadItem; | 51 using content::DownloadItem; |
| 55 using safe_browsing::DownloadFileType; | 52 using safe_browsing::DownloadFileType; |
| 56 | 53 |
| 57 namespace { | 54 namespace { |
| 58 | 55 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 73 (first_visit.LocalMidnight() < base::Time::Now().LocalMidnight())); | 70 (first_visit.LocalMidnight() < base::Time::Now().LocalMidnight())); |
| 74 } | 71 } |
| 75 | 72 |
| 76 #if defined(OS_WIN) | 73 #if defined(OS_WIN) |
| 77 // Keeps track of whether Adobe Reader is up to date. | 74 // Keeps track of whether Adobe Reader is up to date. |
| 78 bool g_is_adobe_reader_up_to_date_ = false; | 75 bool g_is_adobe_reader_up_to_date_ = false; |
| 79 #endif | 76 #endif |
| 80 | 77 |
| 81 } // namespace | 78 } // namespace |
| 82 | 79 |
| 83 DownloadTargetInfo::DownloadTargetInfo() | |
| 84 : target_disposition(DownloadItem::TARGET_DISPOSITION_OVERWRITE), | |
| 85 danger_type(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS), | |
| 86 danger_level(DownloadFileType::NOT_DANGEROUS), | |
| 87 is_filetype_handled_safely(false) {} | |
| 88 | |
| 89 DownloadTargetInfo::~DownloadTargetInfo() {} | |
| 90 | |
| 91 DownloadTargetDeterminerDelegate::~DownloadTargetDeterminerDelegate() { | 80 DownloadTargetDeterminerDelegate::~DownloadTargetDeterminerDelegate() { |
| 92 } | 81 } |
| 93 | 82 |
| 94 DownloadTargetDeterminer::DownloadTargetDeterminer( | 83 DownloadTargetDeterminer::DownloadTargetDeterminer( |
| 95 DownloadItem* download, | 84 DownloadItem* download, |
| 96 const base::FilePath& initial_virtual_path, | 85 const base::FilePath& initial_virtual_path, |
| 86 DownloadPathReservationTracker::FilenameConflictAction conflict_action, |
| 97 DownloadPrefs* download_prefs, | 87 DownloadPrefs* download_prefs, |
| 98 DownloadTargetDeterminerDelegate* delegate, | 88 DownloadTargetDeterminerDelegate* delegate, |
| 99 const CompletionCallback& callback) | 89 const CompletionCallback& callback) |
| 100 : next_state_(STATE_GENERATE_TARGET_PATH), | 90 : next_state_(STATE_GENERATE_TARGET_PATH), |
| 101 should_prompt_(false), | 91 confirmation_reason_(DownloadConfirmationReason::NONE), |
| 102 should_notify_extensions_(false), | 92 should_notify_extensions_(false), |
| 103 create_target_directory_(false), | 93 create_target_directory_(false), |
| 104 conflict_action_(DownloadPathReservationTracker::OVERWRITE), | 94 conflict_action_(conflict_action), |
| 105 danger_type_(download->GetDangerType()), | 95 danger_type_(download->GetDangerType()), |
| 106 danger_level_(DownloadFileType::NOT_DANGEROUS), | 96 danger_level_(DownloadFileType::NOT_DANGEROUS), |
| 107 virtual_path_(initial_virtual_path), | 97 virtual_path_(initial_virtual_path), |
| 108 is_filetype_handled_safely_(false), | 98 is_filetype_handled_safely_(false), |
| 99 result_(DownloadTargetResult::SUCCESS), |
| 109 download_(download), | 100 download_(download), |
| 110 is_resumption_(download_->GetLastReason() != | 101 is_resumption_(download_->GetLastReason() != |
| 111 content::DOWNLOAD_INTERRUPT_REASON_NONE && | 102 content::DOWNLOAD_INTERRUPT_REASON_NONE && |
| 112 !initial_virtual_path.empty()), | 103 !initial_virtual_path.empty()), |
| 113 download_prefs_(download_prefs), | 104 download_prefs_(download_prefs), |
| 114 delegate_(delegate), | 105 delegate_(delegate), |
| 115 completion_callback_(callback), | 106 completion_callback_(callback), |
| 116 weak_ptr_factory_(this) { | 107 weak_ptr_factory_(this) { |
| 117 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 108 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 118 DCHECK(download_); | 109 DCHECK(download_); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 139 case STATE_GENERATE_TARGET_PATH: | 130 case STATE_GENERATE_TARGET_PATH: |
| 140 result = DoGenerateTargetPath(); | 131 result = DoGenerateTargetPath(); |
| 141 break; | 132 break; |
| 142 case STATE_NOTIFY_EXTENSIONS: | 133 case STATE_NOTIFY_EXTENSIONS: |
| 143 result = DoNotifyExtensions(); | 134 result = DoNotifyExtensions(); |
| 144 break; | 135 break; |
| 145 case STATE_RESERVE_VIRTUAL_PATH: | 136 case STATE_RESERVE_VIRTUAL_PATH: |
| 146 result = DoReserveVirtualPath(); | 137 result = DoReserveVirtualPath(); |
| 147 break; | 138 break; |
| 148 case STATE_PROMPT_USER_FOR_DOWNLOAD_PATH: | 139 case STATE_PROMPT_USER_FOR_DOWNLOAD_PATH: |
| 149 result = DoPromptUserForDownloadPath(); | 140 result = DoRequestConfirmation(); |
| 150 break; | 141 break; |
| 151 case STATE_DETERMINE_LOCAL_PATH: | 142 case STATE_DETERMINE_LOCAL_PATH: |
| 152 result = DoDetermineLocalPath(); | 143 result = DoDetermineLocalPath(); |
| 153 break; | 144 break; |
| 154 case STATE_DETERMINE_MIME_TYPE: | 145 case STATE_DETERMINE_MIME_TYPE: |
| 155 result = DoDetermineMimeType(); | 146 result = DoDetermineMimeType(); |
| 156 break; | 147 break; |
| 157 case STATE_DETERMINE_IF_HANDLED_SAFELY_BY_BROWSER: | 148 case STATE_DETERMINE_IF_HANDLED_SAFELY_BY_BROWSER: |
| 158 result = DoDetermineIfHandledSafely(); | 149 result = DoDetermineIfHandledSafely(); |
| 159 break; | 150 break; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 172 case STATE_NONE: | 163 case STATE_NONE: |
| 173 NOTREACHED(); | 164 NOTREACHED(); |
| 174 return; | 165 return; |
| 175 } | 166 } |
| 176 } while (result == CONTINUE); | 167 } while (result == CONTINUE); |
| 177 // Note that if a callback completes synchronously, the handler will still | 168 // Note that if a callback completes synchronously, the handler will still |
| 178 // return QUIT_DOLOOP. In this case, an inner DoLoop() may complete the target | 169 // return QUIT_DOLOOP. In this case, an inner DoLoop() may complete the target |
| 179 // determination and delete |this|. | 170 // determination and delete |this|. |
| 180 | 171 |
| 181 if (result == COMPLETE) | 172 if (result == COMPLETE) |
| 182 ScheduleCallbackAndDeleteSelf(); | 173 ScheduleCallbackAndDeleteSelf(result_); |
| 183 } | 174 } |
| 184 | 175 |
| 185 DownloadTargetDeterminer::Result | 176 DownloadTargetDeterminer::Result |
| 186 DownloadTargetDeterminer::DoGenerateTargetPath() { | 177 DownloadTargetDeterminer::DoGenerateTargetPath() { |
| 187 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 178 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 188 DCHECK(local_path_.empty()); | 179 DCHECK(local_path_.empty()); |
| 189 DCHECK(!should_prompt_); | 180 DCHECK_EQ(confirmation_reason_, DownloadConfirmationReason::NONE); |
| 190 DCHECK(!should_notify_extensions_); | 181 DCHECK(!should_notify_extensions_); |
| 191 DCHECK_EQ(DownloadPathReservationTracker::OVERWRITE, conflict_action_); | |
| 192 bool is_forced_path = !download_->GetForcedFilePath().empty(); | 182 bool is_forced_path = !download_->GetForcedFilePath().empty(); |
| 193 | 183 |
| 194 next_state_ = STATE_NOTIFY_EXTENSIONS; | 184 next_state_ = STATE_NOTIFY_EXTENSIONS; |
| 195 | 185 |
| 196 if (!virtual_path_.empty() && HasPromptedForPath() && !is_forced_path) { | 186 if (!virtual_path_.empty() && HasPromptedForPath() && !is_forced_path) { |
| 197 // The download is being resumed and the user has already been prompted for | 187 // The download is being resumed and the user has already been prompted for |
| 198 // a path. Assume that it's okay to overwrite the file if there's a conflict | 188 // a path. Assume that it's okay to overwrite the file if there's a conflict |
| 199 // and reuse the selection. | 189 // and reuse the selection. |
| 200 should_prompt_ = ShouldPromptForDownload(virtual_path_); | 190 confirmation_reason_ = ShouldPromptForDownload(virtual_path_); |
| 191 conflict_action_ = DownloadPathReservationTracker::OVERWRITE; |
| 201 } else if (!is_forced_path) { | 192 } else if (!is_forced_path) { |
| 202 // If we don't have a forced path, we should construct a path for the | 193 // If we don't have a forced path, we should construct a path for the |
| 203 // download. Forced paths are only specified for programmatic downloads | 194 // download. Forced paths are only specified for programmatic downloads |
| 204 // (WebStore, Drag&Drop). Treat the path as a virtual path. We will | 195 // (WebStore, Drag&Drop). Treat the path as a virtual path. We will |
| 205 // eventually determine whether this is a local path and if not, figure out | 196 // eventually determine whether this is a local path and if not, figure out |
| 206 // a local path. | 197 // a local path. |
| 207 | 198 |
| 208 std::string suggested_filename = download_->GetSuggestedFilename(); | 199 std::string suggested_filename = download_->GetSuggestedFilename(); |
| 209 if (suggested_filename.empty() && | 200 if (suggested_filename.empty() && |
| 210 download_->GetMimeType() == "application/x-x509-user-cert") { | 201 download_->GetMimeType() == "application/x-x509-user-cert") { |
| 211 suggested_filename = "user.crt"; | 202 suggested_filename = "user.crt"; |
| 212 } | 203 } |
| 213 | 204 |
| 214 std::string default_filename( | 205 std::string default_filename( |
| 215 l10n_util::GetStringUTF8(IDS_DEFAULT_DOWNLOAD_FILENAME)); | 206 l10n_util::GetStringUTF8(IDS_DEFAULT_DOWNLOAD_FILENAME)); |
| 216 base::FilePath generated_filename = net::GenerateFileName( | 207 base::FilePath generated_filename = net::GenerateFileName( |
| 217 download_->GetURL(), | 208 download_->GetURL(), |
| 218 download_->GetContentDisposition(), | 209 download_->GetContentDisposition(), |
| 219 GetProfile()->GetPrefs()->GetString(prefs::kDefaultCharset), | 210 GetProfile()->GetPrefs()->GetString(prefs::kDefaultCharset), |
| 220 suggested_filename, | 211 suggested_filename, |
| 221 download_->GetMimeType(), | 212 download_->GetMimeType(), |
| 222 default_filename); | 213 default_filename); |
| 223 should_prompt_ = ShouldPromptForDownload(generated_filename); | 214 confirmation_reason_ = ShouldPromptForDownload(generated_filename); |
| 224 base::FilePath target_directory; | 215 base::FilePath target_directory; |
| 225 if (should_prompt_) { | 216 if (confirmation_reason_ != DownloadConfirmationReason::NONE) { |
| 226 DCHECK(!download_prefs_->IsDownloadPathManaged()); | 217 DCHECK(!download_prefs_->IsDownloadPathManaged()); |
| 227 // If the user is going to be prompted and the user has been prompted | 218 // If the user is going to be prompted and the user has been prompted |
| 228 // before, then always prefer the last directory that the user selected. | 219 // before, then always prefer the last directory that the user selected. |
| 229 target_directory = download_prefs_->SaveFilePath(); | 220 target_directory = download_prefs_->SaveFilePath(); |
| 230 } else { | 221 } else { |
| 231 target_directory = download_prefs_->DownloadPath(); | 222 target_directory = download_prefs_->DownloadPath(); |
| 232 } | 223 } |
| 233 virtual_path_ = target_directory.Append(generated_filename); | 224 virtual_path_ = target_directory.Append(generated_filename); |
| 234 #if defined(OS_ANDROID) | |
| 235 conflict_action_ = DownloadPathReservationTracker::PROMPT; | |
| 236 #else | |
| 237 conflict_action_ = DownloadPathReservationTracker::UNIQUIFY; | |
| 238 #endif | |
| 239 should_notify_extensions_ = true; | 225 should_notify_extensions_ = true; |
| 240 } else { | 226 } else { |
| 227 conflict_action_ = DownloadPathReservationTracker::OVERWRITE; |
| 241 virtual_path_ = download_->GetForcedFilePath(); | 228 virtual_path_ = download_->GetForcedFilePath(); |
| 242 // If this is a resumed download which was previously interrupted due to an | 229 // If this is a resumed download which was previously interrupted due to an |
| 243 // issue with the forced path, the user is still not prompted. If the path | 230 // issue with the forced path, the user is still not prompted. If the path |
| 244 // supplied to a programmatic download is invalid, then the caller needs to | 231 // supplied to a programmatic download is invalid, then the caller needs to |
| 245 // intervene. | 232 // intervene. |
| 246 } | 233 } |
| 247 DCHECK(virtual_path_.IsAbsolute()); | 234 DCHECK(virtual_path_.IsAbsolute()); |
| 248 DVLOG(20) << "Generated virtual path: " << virtual_path_.AsUTF8Unsafe(); | 235 DVLOG(20) << "Generated virtual path: " << virtual_path_.AsUTF8Unsafe(); |
| 249 | 236 |
| 250 return CONTINUE; | 237 return CONTINUE; |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 310 return CONTINUE; | 297 return CONTINUE; |
| 311 | 298 |
| 312 delegate_->ReserveVirtualPath( | 299 delegate_->ReserveVirtualPath( |
| 313 download_, virtual_path_, create_target_directory_, conflict_action_, | 300 download_, virtual_path_, create_target_directory_, conflict_action_, |
| 314 base::Bind(&DownloadTargetDeterminer::ReserveVirtualPathDone, | 301 base::Bind(&DownloadTargetDeterminer::ReserveVirtualPathDone, |
| 315 weak_ptr_factory_.GetWeakPtr())); | 302 weak_ptr_factory_.GetWeakPtr())); |
| 316 return QUIT_DOLOOP; | 303 return QUIT_DOLOOP; |
| 317 } | 304 } |
| 318 | 305 |
| 319 void DownloadTargetDeterminer::ReserveVirtualPathDone( | 306 void DownloadTargetDeterminer::ReserveVirtualPathDone( |
| 320 const base::FilePath& path, bool verified) { | 307 const base::FilePath& path, |
| 321 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 308 DownloadTargetResult result) { |
| 309 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 322 DVLOG(20) << "Reserved path: " << path.AsUTF8Unsafe() | 310 DVLOG(20) << "Reserved path: " << path.AsUTF8Unsafe() |
| 323 << " Verified:" << verified; | 311 << " Result:" << static_cast<int>(result); |
| 324 DCHECK_EQ(STATE_PROMPT_USER_FOR_DOWNLOAD_PATH, next_state_); | 312 DCHECK_EQ(STATE_PROMPT_USER_FOR_DOWNLOAD_PATH, next_state_); |
| 325 #if BUILDFLAG(ANDROID_JAVA_UI) | 313 |
| 326 if (!verified) { | 314 virtual_path_ = path; |
| 327 if (path.empty()) { | 315 result_ = result; |
| 328 DownloadManagerService::OnDownloadCanceled( | 316 |
| 329 download_, DownloadController::CANCEL_REASON_NO_EXTERNAL_STORAGE); | 317 switch (result) { |
| 330 CancelOnFailureAndDeleteSelf(); | 318 case DownloadTargetResult::SUCCESS: |
| 331 return; | 319 break; |
| 332 } | 320 |
| 333 if (!download_->GetWebContents()) { | 321 case DownloadTargetResult::PATH_NOT_WRITEABLE: |
| 334 // If we cannot reserve the path and the WebContent is already gone, there | 322 confirmation_reason_ = DownloadConfirmationReason::TARGET_NOT_WRITEABLE; |
| 335 // is no way to prompt user for an infobar. This could happen after chrome | 323 break; |
| 336 // gets killed, and user tries to resume a download while another app has | 324 |
| 337 // created the target file (not the temporary .crdownload file). | 325 case DownloadTargetResult::NAME_TOO_LONG: |
| 338 DownloadManagerService::OnDownloadCanceled( | 326 confirmation_reason_ = DownloadConfirmationReason::NAME_TOO_LONG; |
| 339 download_, | 327 break; |
| 340 DownloadController::CANCEL_REASON_CANNOT_DETERMINE_DOWNLOAD_TARGET); | 328 |
| 341 CancelOnFailureAndDeleteSelf(); | 329 case DownloadTargetResult::CONFLICT: |
| 342 return; | 330 confirmation_reason_ = DownloadConfirmationReason::TARGET_CONFLICT; |
| 343 } | 331 break; |
| 332 |
| 333 case DownloadTargetResult::USER_CANCELED: |
| 334 case DownloadTargetResult::UNEXPECTED: |
| 335 // These are not considered recoverable errors. The download needs to be |
| 336 // interrupted. |
| 337 break; |
| 344 } | 338 } |
| 345 #endif | 339 |
| 346 should_prompt_ = (should_prompt_ || !verified); | |
| 347 virtual_path_ = path; | |
| 348 DoLoop(); | 340 DoLoop(); |
| 349 } | 341 } |
| 350 | 342 |
| 351 DownloadTargetDeterminer::Result | 343 DownloadTargetDeterminer::Result |
| 352 DownloadTargetDeterminer::DoPromptUserForDownloadPath() { | 344 DownloadTargetDeterminer::DoRequestConfirmation() { |
| 353 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 345 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 354 DCHECK(!virtual_path_.empty()); | 346 DCHECK(!virtual_path_.empty()); |
| 355 | 347 |
| 356 next_state_ = STATE_DETERMINE_LOCAL_PATH; | 348 next_state_ = STATE_DETERMINE_LOCAL_PATH; |
| 357 | 349 |
| 358 // Avoid prompting for a download if it isn't in-progress. The user will be | 350 // Avoid prompting for a download if it isn't in-progress. The user will be |
| 359 // prompted once the download is resumed and headers are available. | 351 // prompted once the download is resumed and headers are available. |
| 360 if (should_prompt_ && download_->GetState() == DownloadItem::IN_PROGRESS) { | 352 if (confirmation_reason_ != DownloadConfirmationReason::NONE && |
| 361 delegate_->PromptUserForDownloadPath( | 353 download_->GetState() == DownloadItem::IN_PROGRESS) { |
| 362 download_, | 354 delegate_->RequestConfirmation( |
| 363 virtual_path_, | 355 download_, virtual_path_, confirmation_reason_, |
| 364 base::Bind(&DownloadTargetDeterminer::PromptUserForDownloadPathDone, | 356 base::Bind(&DownloadTargetDeterminer::RequestConfirmationDone, |
| 365 weak_ptr_factory_.GetWeakPtr())); | 357 weak_ptr_factory_.GetWeakPtr())); |
| 366 return QUIT_DOLOOP; | 358 return QUIT_DOLOOP; |
| 367 } | 359 } |
| 368 return CONTINUE; | 360 return CONTINUE; |
| 369 } | 361 } |
| 370 | 362 |
| 371 void DownloadTargetDeterminer::PromptUserForDownloadPathDone( | 363 void DownloadTargetDeterminer::RequestConfirmationDone( |
| 364 DownloadConfirmationResult result, |
| 372 const base::FilePath& virtual_path) { | 365 const base::FilePath& virtual_path) { |
| 373 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 366 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 374 DVLOG(20) << "User selected path:" << virtual_path.AsUTF8Unsafe(); | 367 DVLOG(20) << "User selected path:" << virtual_path.AsUTF8Unsafe(); |
| 375 if (virtual_path.empty()) { | 368 if (result == DownloadConfirmationResult::CANCELED) { |
| 376 CancelOnFailureAndDeleteSelf(); | 369 ScheduleCallbackAndDeleteSelf(DownloadTargetResult::USER_CANCELED); |
| 377 return; | 370 return; |
| 378 } | 371 } |
| 372 DCHECK(!virtual_path.empty()); |
| 379 DCHECK_EQ(STATE_DETERMINE_LOCAL_PATH, next_state_); | 373 DCHECK_EQ(STATE_DETERMINE_LOCAL_PATH, next_state_); |
| 380 | 374 |
| 375 // If the user wasn't prompted, then we need to clear the |
| 376 // confirmation_reason_. This way it's clear that user has not given consent |
| 377 // to download this resource. |
| 378 if (result == DownloadConfirmationResult::CONTINUE_WITHOUT_CONFIRMATION) |
| 379 confirmation_reason_ = DownloadConfirmationReason::NONE; |
| 380 |
| 381 result_ = DownloadTargetResult::SUCCESS; |
| 381 virtual_path_ = virtual_path; | 382 virtual_path_ = virtual_path; |
| 382 download_prefs_->SetSaveFilePath(virtual_path_.DirName()); | 383 download_prefs_->SetSaveFilePath(virtual_path_.DirName()); |
| 383 DoLoop(); | 384 DoLoop(); |
| 384 } | 385 } |
| 385 | 386 |
| 386 DownloadTargetDeterminer::Result | 387 DownloadTargetDeterminer::Result |
| 387 DownloadTargetDeterminer::DoDetermineLocalPath() { | 388 DownloadTargetDeterminer::DoDetermineLocalPath() { |
| 388 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 389 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 389 DCHECK(!virtual_path_.empty()); | 390 DCHECK(!virtual_path_.empty()); |
| 390 DCHECK(local_path_.empty()); | 391 DCHECK(local_path_.empty()); |
| 391 | 392 |
| 392 next_state_ = STATE_DETERMINE_MIME_TYPE; | 393 next_state_ = STATE_DETERMINE_MIME_TYPE; |
| 393 | 394 |
| 394 delegate_->DetermineLocalPath( | 395 delegate_->DetermineLocalPath( |
| 395 download_, | 396 download_, |
| 396 virtual_path_, | 397 virtual_path_, |
| 397 base::Bind(&DownloadTargetDeterminer::DetermineLocalPathDone, | 398 base::Bind(&DownloadTargetDeterminer::DetermineLocalPathDone, |
| 398 weak_ptr_factory_.GetWeakPtr())); | 399 weak_ptr_factory_.GetWeakPtr())); |
| 399 return QUIT_DOLOOP; | 400 return QUIT_DOLOOP; |
| 400 } | 401 } |
| 401 | 402 |
| 402 void DownloadTargetDeterminer::DetermineLocalPathDone( | 403 void DownloadTargetDeterminer::DetermineLocalPathDone( |
| 403 const base::FilePath& local_path) { | 404 const base::FilePath& local_path) { |
| 404 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 405 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 405 DVLOG(20) << "Local path: " << local_path.AsUTF8Unsafe(); | 406 DVLOG(20) << "Local path: " << local_path.AsUTF8Unsafe(); |
| 406 if (local_path.empty()) { | 407 if (local_path.empty()) { |
| 407 // Path subsitution failed. | 408 // Path subsitution failed. Usually caused by something going wrong with the |
| 408 CancelOnFailureAndDeleteSelf(); | 409 // Google Drive logic (e.g. filesystem error while trying to create the |
| 410 // cache file). We are going to return a generic error here since a more |
| 411 // specific one is unlikely to be helpful to the user. |
| 412 ScheduleCallbackAndDeleteSelf(DownloadTargetResult::UNEXPECTED); |
| 409 return; | 413 return; |
| 410 } | 414 } |
| 411 DCHECK_EQ(STATE_DETERMINE_MIME_TYPE, next_state_); | 415 DCHECK_EQ(STATE_DETERMINE_MIME_TYPE, next_state_); |
| 412 | 416 |
| 413 local_path_ = local_path; | 417 local_path_ = local_path; |
| 414 DoLoop(); | 418 DoLoop(); |
| 415 } | 419 } |
| 416 | 420 |
| 417 DownloadTargetDeterminer::Result | 421 DownloadTargetDeterminer::Result |
| 418 DownloadTargetDeterminer::DoDetermineMimeType() { | 422 DownloadTargetDeterminer::DoDetermineMimeType() { |
| (...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 743 #endif | 747 #endif |
| 744 unconfirmed_format.append(kUnconfirmedFormatSuffix); | 748 unconfirmed_format.append(kUnconfirmedFormatSuffix); |
| 745 | 749 |
| 746 base::FilePath::StringType file_name = base::StringPrintf( | 750 base::FilePath::StringType file_name = base::StringPrintf( |
| 747 unconfirmed_format.c_str(), | 751 unconfirmed_format.c_str(), |
| 748 base::RandInt(0, kUnconfirmedUniquifierRange)); | 752 base::RandInt(0, kUnconfirmedUniquifierRange)); |
| 749 intermediate_path_ = local_path_.DirName().Append(file_name); | 753 intermediate_path_ = local_path_.DirName().Append(file_name); |
| 750 return COMPLETE; | 754 return COMPLETE; |
| 751 } | 755 } |
| 752 | 756 |
| 753 void DownloadTargetDeterminer::ScheduleCallbackAndDeleteSelf() { | 757 void DownloadTargetDeterminer::ScheduleCallbackAndDeleteSelf( |
| 758 DownloadTargetResult result) { |
| 754 DCHECK(download_); | 759 DCHECK(download_); |
| 755 DVLOG(20) << "Scheduling callback. Virtual:" << virtual_path_.AsUTF8Unsafe() | 760 DVLOG(20) << "Scheduling callback. Virtual:" << virtual_path_.AsUTF8Unsafe() |
| 756 << " Local:" << local_path_.AsUTF8Unsafe() | 761 << " Local:" << local_path_.AsUTF8Unsafe() |
| 757 << " Intermediate:" << intermediate_path_.AsUTF8Unsafe() | 762 << " Intermediate:" << intermediate_path_.AsUTF8Unsafe() |
| 758 << " Should prompt:" << should_prompt_ | 763 << " Confirmation reason:" << static_cast<int>(confirmation_reason_) |
| 759 << " Danger type:" << danger_type_ | 764 << " Danger type:" << danger_type_ |
| 760 << " Danger level:" << danger_level_; | 765 << " Danger level:" << danger_level_ |
| 766 << " Result:" << static_cast<int>(result); |
| 761 std::unique_ptr<DownloadTargetInfo> target_info(new DownloadTargetInfo); | 767 std::unique_ptr<DownloadTargetInfo> target_info(new DownloadTargetInfo); |
| 762 | 768 |
| 763 target_info->target_path = local_path_; | 769 target_info->target_path = local_path_; |
| 770 target_info->result = result; |
| 764 target_info->target_disposition = | 771 target_info->target_disposition = |
| 765 (HasPromptedForPath() || should_prompt_ | 772 (HasPromptedForPath() || |
| 773 confirmation_reason_ != DownloadConfirmationReason::NONE |
| 766 ? DownloadItem::TARGET_DISPOSITION_PROMPT | 774 ? DownloadItem::TARGET_DISPOSITION_PROMPT |
| 767 : DownloadItem::TARGET_DISPOSITION_OVERWRITE); | 775 : DownloadItem::TARGET_DISPOSITION_OVERWRITE); |
| 768 target_info->danger_type = danger_type_; | 776 target_info->danger_type = danger_type_; |
| 769 target_info->danger_level = danger_level_; | 777 target_info->danger_level = danger_level_; |
| 770 target_info->intermediate_path = intermediate_path_; | 778 target_info->intermediate_path = intermediate_path_; |
| 771 target_info->mime_type = mime_type_; | 779 target_info->mime_type = mime_type_; |
| 772 target_info->is_filetype_handled_safely = is_filetype_handled_safely_; | 780 target_info->is_filetype_handled_safely = is_filetype_handled_safely_; |
| 773 | 781 |
| 774 base::ThreadTaskRunnerHandle::Get()->PostTask( | 782 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 775 FROM_HERE, base::Bind(completion_callback_, base::Passed(&target_info))); | 783 FROM_HERE, base::Bind(completion_callback_, base::Passed(&target_info))); |
| 776 completion_callback_.Reset(); | 784 completion_callback_.Reset(); |
| 777 delete this; | 785 delete this; |
| 778 } | 786 } |
| 779 | 787 |
| 780 void DownloadTargetDeterminer::CancelOnFailureAndDeleteSelf() { | |
| 781 // Path substitution failed. | |
| 782 virtual_path_.clear(); | |
| 783 local_path_.clear(); | |
| 784 intermediate_path_.clear(); | |
| 785 ScheduleCallbackAndDeleteSelf(); | |
| 786 } | |
| 787 | |
| 788 Profile* DownloadTargetDeterminer::GetProfile() const { | 788 Profile* DownloadTargetDeterminer::GetProfile() const { |
| 789 DCHECK(download_->GetBrowserContext()); | 789 DCHECK(download_->GetBrowserContext()); |
| 790 return Profile::FromBrowserContext(download_->GetBrowserContext()); | 790 return Profile::FromBrowserContext(download_->GetBrowserContext()); |
| 791 } | 791 } |
| 792 | 792 |
| 793 bool DownloadTargetDeterminer::ShouldPromptForDownload( | 793 DownloadConfirmationReason DownloadTargetDeterminer::ShouldPromptForDownload( |
| 794 const base::FilePath& filename) const { | 794 const base::FilePath& filename) const { |
| 795 #if BUILDFLAG(ANDROID_JAVA_UI) | |
| 796 // Don't prompt user about saving path on Android. | |
| 797 // TODO(qinmin): show an error toast to warn user in certain cases. | |
| 798 return false; | |
| 799 #endif | |
| 800 if (is_resumption_) { | 795 if (is_resumption_) { |
| 801 // For resumed downloads, if the target disposition or prefs require | 796 // For resumed downloads, if the target disposition or prefs require |
| 802 // prompting, the user has already been prompted. Try to respect the user's | 797 // prompting, the user has already been prompted. Try to respect the user's |
| 803 // selection, unless we've discovered that the target path cannot be used | 798 // selection, unless we've discovered that the target path cannot be used |
| 804 // for some reason. | 799 // for some reason. |
| 805 content::DownloadInterruptReason reason = download_->GetLastReason(); | 800 content::DownloadInterruptReason reason = download_->GetLastReason(); |
| 806 return (reason == content::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED || | 801 switch (reason) { |
| 807 reason == content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE || | 802 case content::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED: |
| 808 reason == content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE); | 803 return DownloadConfirmationReason::TARGET_NOT_WRITEABLE; |
| 804 |
| 805 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE: |
| 806 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE: |
| 807 return DownloadConfirmationReason::TARGET_NO_SPACE; |
| 808 |
| 809 default: |
| 810 return DownloadConfirmationReason::NONE; |
| 811 } |
| 809 } | 812 } |
| 810 | 813 |
| 811 // If the download path is forced, don't prompt. | 814 // If the download path is forced, don't prompt. |
| 812 if (!download_->GetForcedFilePath().empty()) { | 815 if (!download_->GetForcedFilePath().empty()) { |
| 813 // 'Save As' downloads shouldn't have a forced path. | 816 // 'Save As' downloads shouldn't have a forced path. |
| 814 DCHECK(DownloadItem::TARGET_DISPOSITION_PROMPT != | 817 DCHECK(DownloadItem::TARGET_DISPOSITION_PROMPT != |
| 815 download_->GetTargetDisposition()); | 818 download_->GetTargetDisposition()); |
| 816 return false; | 819 return DownloadConfirmationReason::NONE; |
| 817 } | 820 } |
| 818 | 821 |
| 819 // Don't ask where to save if the download path is managed. Even if the user | 822 // Don't ask where to save if the download path is managed. Even if the user |
| 820 // wanted to be prompted for "all" downloads, or if this was a 'Save As' | 823 // wanted to be prompted for "all" downloads, or if this was a 'Save As' |
| 821 // download. | 824 // download. |
| 822 if (download_prefs_->IsDownloadPathManaged()) | 825 if (download_prefs_->IsDownloadPathManaged()) |
| 823 return false; | 826 return DownloadConfirmationReason::NONE; |
| 824 | 827 |
| 825 // Prompt if this is a 'Save As' download. | 828 // Prompt if this is a 'Save As' download. |
| 826 if (download_->GetTargetDisposition() == | 829 if (download_->GetTargetDisposition() == |
| 827 DownloadItem::TARGET_DISPOSITION_PROMPT) | 830 DownloadItem::TARGET_DISPOSITION_PROMPT) |
| 828 return true; | 831 return DownloadConfirmationReason::SAVE_AS; |
| 829 | 832 |
| 830 // Check if the user has the "Always prompt for download location" preference | 833 #if defined(ENABLE_EXTENSIONS) |
| 831 // set. If so we prompt for most downloads except for the following scenarios: | 834 // Don't prompt for extension downloads. |
| 832 // 1) Extension installation. Note that we only care here about the case where | 835 if (download_crx_util::IsExtensionDownload(*download_) || |
| 833 // an extension is installed, not when one is downloaded with "save as...". | 836 filename.MatchesExtension(extensions::kExtensionFileExtension)) |
| 834 // 2) Filetypes marked "always open." If the user just wants this file opened, | 837 return DownloadConfirmationReason::NONE; |
| 835 // don't bother asking where to keep it. | 838 #endif |
| 836 if (download_prefs_->PromptForDownload() && | |
| 837 !download_crx_util::IsExtensionDownload(*download_) && | |
| 838 !filename.MatchesExtension(extensions::kExtensionFileExtension) && | |
| 839 !download_prefs_->IsAutoOpenEnabledBasedOnExtension(filename)) | |
| 840 return true; | |
| 841 | 839 |
| 842 // Otherwise, don't prompt. Note that the user might still be prompted if | 840 // Don't prompt for file types that are marked for opening automatically. |
| 843 // there are unresolved conflicts during path reservation (e.g. due to the | 841 if (download_prefs_->IsAutoOpenEnabledBasedOnExtension(filename)) |
| 844 // target path being unwriteable or because there are too many conflicting | 842 return DownloadConfirmationReason::NONE; |
| 845 // files), or if an extension signals that the user be prompted on a filename | 843 |
| 846 // conflict. | 844 // For everything else, prompting is controlled by the PromptForDownload pref. |
| 847 return false; | 845 // The user may still be prompted even if this pref is disabled due to, for |
| 846 // example, there being an unresolvable filename conflict or the target path |
| 847 // is not writeable. |
| 848 return download_prefs_->PromptForDownload() |
| 849 ? DownloadConfirmationReason::PREFERENCE |
| 850 : DownloadConfirmationReason::NONE; |
| 848 } | 851 } |
| 849 | 852 |
| 850 bool DownloadTargetDeterminer::HasPromptedForPath() const { | 853 bool DownloadTargetDeterminer::HasPromptedForPath() const { |
| 851 return (is_resumption_ && download_->GetTargetDisposition() == | 854 return (is_resumption_ && download_->GetTargetDisposition() == |
| 852 DownloadItem::TARGET_DISPOSITION_PROMPT); | 855 DownloadItem::TARGET_DISPOSITION_PROMPT); |
| 853 } | 856 } |
| 854 | 857 |
| 855 DownloadFileType::DangerLevel DownloadTargetDeterminer::GetDangerLevel( | 858 DownloadFileType::DangerLevel DownloadTargetDeterminer::GetDangerLevel( |
| 856 PriorVisitsToReferrer visits) const { | 859 PriorVisitsToReferrer visits) const { |
| 857 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 860 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 858 | 861 |
| 859 // If the user has has been prompted or will be, assume that the user has | 862 // If the user has has been prompted or will be, assume that the user has |
| 860 // approved the download. A programmatic download is considered safe unless it | 863 // approved the download. A programmatic download is considered safe unless it |
| 861 // contains malware. | 864 // contains malware. |
| 862 if (HasPromptedForPath() || should_prompt_ || | 865 if (HasPromptedForPath() || |
| 866 confirmation_reason_ != DownloadConfirmationReason::NONE || |
| 863 !download_->GetForcedFilePath().empty()) | 867 !download_->GetForcedFilePath().empty()) |
| 864 return DownloadFileType::NOT_DANGEROUS; | 868 return DownloadFileType::NOT_DANGEROUS; |
| 865 | 869 |
| 866 const bool is_extension_download = | 870 const bool is_extension_download = |
| 867 download_crx_util::IsExtensionDownload(*download_); | 871 download_crx_util::IsExtensionDownload(*download_); |
| 868 | 872 |
| 869 // User-initiated extension downloads from pref-whitelisted sources are not | 873 // User-initiated extension downloads from pref-whitelisted sources are not |
| 870 // considered dangerous. | 874 // considered dangerous. |
| 871 if (download_->HasUserGesture() && | 875 if (download_->HasUserGesture() && |
| 872 is_extension_download && | 876 is_extension_download && |
| 873 download_crx_util::OffStoreInstallAllowedByPrefs( | 877 download_crx_util::OffStoreInstallAllowedByPrefs( |
| 874 GetProfile(), *download_)) { | 878 GetProfile(), *download_)) { |
| 875 return DownloadFileType::NOT_DANGEROUS; | 879 return DownloadFileType::NOT_DANGEROUS; |
| 876 } | 880 } |
| 877 | 881 |
| 878 #if defined(ENABLE_EXTENSIONS) | 882 #if defined(ENABLE_EXTENSIONS) |
| 879 // Extensions that are not from the gallery are considered dangerous. | 883 // Extensions that are not from the gallery are considered dangerous. |
| 880 // When off-store install is disabled we skip this, since in this case, we | 884 // Exception: If off-store install is disabled, then extension downloads are |
| 881 // will not offer to install the extension. | 885 // not considered dangerous since we will not offer to install these. |
| 882 if (extensions::FeatureSwitch::easy_off_store_install()->IsEnabled() && | 886 if (extensions::FeatureSwitch::easy_off_store_install()->IsEnabled() && |
| 883 is_extension_download && | 887 is_extension_download && |
| 884 !extensions::WebstoreInstaller::GetAssociatedApproval(*download_)) { | 888 !extensions::WebstoreInstaller::GetAssociatedApproval(*download_)) { |
| 885 return DownloadFileType::ALLOW_ON_USER_GESTURE; | 889 return DownloadFileType::ALLOW_ON_USER_GESTURE; |
| 886 } | 890 } |
| 887 #endif | 891 #endif |
| 888 | 892 |
| 889 // Anything the user has marked auto-open is OK if it's user-initiated. | 893 // Anything the user has marked auto-open is OK if it's user-initiated. |
| 890 if (download_prefs_->IsAutoOpenEnabledBasedOnExtension(virtual_path_) && | 894 if (download_prefs_->IsAutoOpenEnabledBasedOnExtension(virtual_path_) && |
| 891 download_->HasUserGesture()) | 895 download_->HasUserGesture()) |
| (...skipping 21 matching lines...) Expand all Loading... |
| 913 ui::PAGE_TRANSITION_FROM_ADDRESS_BAR) != 0 || | 917 ui::PAGE_TRANSITION_FROM_ADDRESS_BAR) != 0 || |
| 914 (download_->HasUserGesture() && visits == VISITED_REFERRER))) | 918 (download_->HasUserGesture() && visits == VISITED_REFERRER))) |
| 915 return DownloadFileType::NOT_DANGEROUS; | 919 return DownloadFileType::NOT_DANGEROUS; |
| 916 return danger_level; | 920 return danger_level; |
| 917 } | 921 } |
| 918 | 922 |
| 919 void DownloadTargetDeterminer::OnDownloadDestroyed( | 923 void DownloadTargetDeterminer::OnDownloadDestroyed( |
| 920 DownloadItem* download) { | 924 DownloadItem* download) { |
| 921 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 925 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 922 DCHECK_EQ(download_, download); | 926 DCHECK_EQ(download_, download); |
| 923 CancelOnFailureAndDeleteSelf(); | 927 ScheduleCallbackAndDeleteSelf(DownloadTargetResult::USER_CANCELED); |
| 924 } | 928 } |
| 925 | 929 |
| 926 // static | 930 // static |
| 927 void DownloadTargetDeterminer::Start(content::DownloadItem* download, | 931 void DownloadTargetDeterminer::Start( |
| 928 const base::FilePath& initial_virtual_path, | 932 content::DownloadItem* download, |
| 929 DownloadPrefs* download_prefs, | 933 const base::FilePath& initial_virtual_path, |
| 930 DownloadTargetDeterminerDelegate* delegate, | 934 DownloadPathReservationTracker::FilenameConflictAction conflict_action, |
| 931 const CompletionCallback& callback) { | 935 DownloadPrefs* download_prefs, |
| 936 DownloadTargetDeterminerDelegate* delegate, |
| 937 const CompletionCallback& callback) { |
| 932 // DownloadTargetDeterminer owns itself and will self destruct when the job is | 938 // DownloadTargetDeterminer owns itself and will self destruct when the job is |
| 933 // complete or the download item is destroyed. The callback is always invoked | 939 // complete or the download item is destroyed. The callback is always invoked |
| 934 // asynchronously. | 940 // asynchronously. |
| 935 new DownloadTargetDeterminer(download, initial_virtual_path, download_prefs, | 941 new DownloadTargetDeterminer(download, initial_virtual_path, conflict_action, |
| 936 delegate, callback); | 942 download_prefs, delegate, callback); |
| 937 } | 943 } |
| 938 | 944 |
| 939 // static | 945 // static |
| 940 base::FilePath DownloadTargetDeterminer::GetCrDownloadPath( | 946 base::FilePath DownloadTargetDeterminer::GetCrDownloadPath( |
| 941 const base::FilePath& suggested_path) { | 947 const base::FilePath& suggested_path) { |
| 942 return base::FilePath(suggested_path.value() + kCrdownloadSuffix); | 948 return base::FilePath(suggested_path.value() + kCrdownloadSuffix); |
| 943 } | 949 } |
| 944 | 950 |
| 945 #if defined(OS_WIN) | 951 #if defined(OS_WIN) |
| 946 // static | 952 // static |
| 947 bool DownloadTargetDeterminer::IsAdobeReaderUpToDate() { | 953 bool DownloadTargetDeterminer::IsAdobeReaderUpToDate() { |
| 948 return g_is_adobe_reader_up_to_date_; | 954 return g_is_adobe_reader_up_to_date_; |
| 949 } | 955 } |
| 950 #endif | 956 #endif |
| OLD | NEW |