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