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 |