OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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_manager.h" | 5 #include "chrome/browser/download/download_manager.h" |
6 | 6 |
7 #include "base/callback.h" | 7 #include "base/callback.h" |
8 #include "base/file_util.h" | 8 #include "base/file_util.h" |
9 #include "base/i18n/case_conversion.h" | 9 #include "base/i18n/case_conversion.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
244 } | 244 } |
245 | 245 |
246 // We have received a message from DownloadFileManager about a new download. We | 246 // We have received a message from DownloadFileManager about a new download. We |
247 // create a download item and store it in our download map, and inform the | 247 // create a download item and store it in our download map, and inform the |
248 // history system of a new download. Since this method can be called while the | 248 // history system of a new download. Since this method can be called while the |
249 // history service thread is still reading the persistent state, we do not | 249 // history service thread is still reading the persistent state, we do not |
250 // insert the new DownloadItem into 'history_downloads_' or inform our | 250 // insert the new DownloadItem into 'history_downloads_' or inform our |
251 // observers at this point. OnCreateDownloadEntryComplete() handles that | 251 // observers at this point. OnCreateDownloadEntryComplete() handles that |
252 // finalization of the the download creation as a callback from the | 252 // finalization of the the download creation as a callback from the |
253 // history thread. | 253 // history thread. |
254 void DownloadManager::StartDownload(DownloadCreateInfo* info) { | 254 void DownloadManager::StartDownload(int32 download_id) { |
255 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 255 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
256 | 256 |
| 257 DownloadItem* download = GetActiveDownloadItem(download_id); |
| 258 if (!download) |
| 259 return; |
| 260 |
257 // Create a client to verify download URL with safebrowsing. | 261 // Create a client to verify download URL with safebrowsing. |
258 // It deletes itself after the callback. | 262 // It deletes itself after the callback. |
259 scoped_refptr<DownloadSBClient> sb_client = new DownloadSBClient( | 263 scoped_refptr<DownloadSBClient> sb_client = new DownloadSBClient( |
260 info->download_id, info->url_chain, info->referrer_url); | 264 download_id, download->url_chain(), download->referrer_url()); |
261 sb_client->CheckDownloadUrl( | 265 sb_client->CheckDownloadUrl( |
262 info, NewCallback(this, &DownloadManager::CheckDownloadUrlDone)); | 266 NewCallback(this, &DownloadManager::CheckDownloadUrlDone)); |
263 } | 267 } |
264 | 268 |
265 void DownloadManager::CheckDownloadUrlDone(DownloadCreateInfo* info, | 269 void DownloadManager::CheckDownloadUrlDone(int32 download_id, |
266 bool is_dangerous_url) { | 270 bool is_dangerous_url) { |
267 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 271 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
268 DCHECK(info); | |
269 | 272 |
270 info->is_dangerous_url = is_dangerous_url; | 273 DownloadItem* download = GetActiveDownloadItem(download_id); |
| 274 if (!download) |
| 275 return; |
| 276 |
| 277 download->set_dangerous_url(is_dangerous_url); |
| 278 |
| 279 DownloadItem::DownloadStateInfo state(*download); |
271 | 280 |
272 // Check whether this download is for an extension install or not. | 281 // Check whether this download is for an extension install or not. |
273 // Allow extensions to be explicitly saved. | 282 // Allow extensions to be explicitly saved. |
274 if (!info->prompt_user_for_save_location) { | 283 if (!state.prompt_user_for_save_location) { |
275 if (UserScript::IsURLUserScript(info->url(), info->mime_type) || | 284 if (UserScript::IsURLUserScript(download->url(), download->mime_type()) || |
276 info->mime_type == Extension::kMimeType) { | 285 (download->mime_type() == Extension::kMimeType)) { |
277 info->is_extension_install = true; | 286 state.is_extension_install = true; |
278 } | 287 } |
279 } | 288 } |
280 | 289 |
281 if (info->save_info.file_path.empty()) { | 290 if (state.force_file_name.empty()) { |
282 FilePath generated_name; | 291 FilePath generated_name; |
283 download_util::GenerateFileNameFromInfo(info, &generated_name); | 292 download_util::GenerateFileNameFromRequest(download->url(), |
| 293 download->content_disposition(), |
| 294 download->referrer_charset(), |
| 295 download->mime_type(), |
| 296 &generated_name); |
284 | 297 |
285 // Freeze the user's preference for showing a Save As dialog. We're going | 298 // Freeze the user's preference for showing a Save As dialog. We're going |
286 // to bounce around a bunch of threads and we don't want to worry about race | 299 // to bounce around a bunch of threads and we don't want to worry about race |
287 // conditions where the user changes this pref out from under us. | 300 // conditions where the user changes this pref out from under us. |
288 if (download_prefs_->PromptForDownload()) { | 301 if (download_prefs_->PromptForDownload()) { |
289 // But ignore the user's preference for the following scenarios: | 302 // But ignore the user's preference for the following scenarios: |
290 // 1) Extension installation. Note that we only care here about the case | 303 // 1) Extension installation. Note that we only care here about the case |
291 // where an extension is installed, not when one is downloaded with | 304 // where an extension is installed, not when one is downloaded with |
292 // "save as...". | 305 // "save as...". |
293 // 2) Filetypes marked "always open." If the user just wants this file | 306 // 2) Filetypes marked "always open." If the user just wants this file |
294 // opened, don't bother asking where to keep it. | 307 // opened, don't bother asking where to keep it. |
295 if (!info->is_extension_install && | 308 if (!state.is_extension_install && |
296 !ShouldOpenFileBasedOnExtension(generated_name)) | 309 !ShouldOpenFileBasedOnExtension(generated_name)) |
297 info->prompt_user_for_save_location = true; | 310 state.prompt_user_for_save_location = true; |
298 } | 311 } |
299 if (download_prefs_->IsDownloadPathManaged()) { | 312 if (download_prefs_->IsDownloadPathManaged()) { |
300 info->prompt_user_for_save_location = false; | 313 state.prompt_user_for_save_location = false; |
301 } | 314 } |
302 | 315 |
303 // Determine the proper path for a download, by either one of the following: | 316 // Determine the proper path for a download, by either one of the following: |
304 // 1) using the default download directory. | 317 // 1) using the default download directory. |
305 // 2) prompting the user. | 318 // 2) prompting the user. |
306 if (info->prompt_user_for_save_location && !last_download_path_.empty()) { | 319 if (state.prompt_user_for_save_location && !last_download_path_.empty()) { |
307 info->suggested_path = last_download_path_; | 320 state.suggested_path = last_download_path_; |
308 } else { | 321 } else { |
309 info->suggested_path = download_prefs_->download_path(); | 322 state.suggested_path = download_prefs_->download_path(); |
310 } | 323 } |
311 info->suggested_path = info->suggested_path.Append(generated_name); | 324 state.suggested_path = state.suggested_path.Append(generated_name); |
312 } else { | 325 } else { |
313 info->suggested_path = info->save_info.file_path; | 326 state.suggested_path = state.force_file_name; |
314 } | 327 } |
315 | 328 |
316 if (!info->prompt_user_for_save_location && | 329 if (!state.prompt_user_for_save_location && state.force_file_name.empty()) { |
317 info->save_info.file_path.empty()) { | 330 state.is_dangerous_file = download_util::IsDangerous( |
318 info->is_dangerous_file = download_util::IsDangerous( | 331 download->url(), |
319 info, profile(), ShouldOpenFileBasedOnExtension(info->suggested_path)); | 332 download->referrer_url(), |
| 333 state.suggested_path, |
| 334 state.has_user_gesture, |
| 335 state.is_extension_install, |
| 336 profile(), |
| 337 ShouldOpenFileBasedOnExtension(state.suggested_path)); |
320 } | 338 } |
321 | 339 |
322 // We need to move over to the download thread because we don't want to stat | 340 // We need to move over to the download thread because we don't want to stat |
323 // the suggested path on the UI thread. | 341 // the suggested path on the UI thread. |
324 // We can only access preferences on the UI thread, so check the download path | 342 // We can only access preferences on the UI thread, so check the download path |
325 // now and pass the value to the FILE thread. | 343 // now and pass the value to the FILE thread. |
326 BrowserThread::PostTask( | 344 BrowserThread::PostTask( |
327 BrowserThread::FILE, FROM_HERE, | 345 BrowserThread::FILE, FROM_HERE, |
328 NewRunnableMethod( | 346 NewRunnableMethod( |
329 this, | 347 this, |
330 &DownloadManager::CheckIfSuggestedPathExists, | 348 &DownloadManager::CheckIfSuggestedPathExists, |
331 info, | 349 download_id, |
| 350 state, |
332 download_prefs()->download_path())); | 351 download_prefs()->download_path())); |
333 } | 352 } |
334 | 353 |
335 void DownloadManager::CheckIfSuggestedPathExists(DownloadCreateInfo* info, | 354 void DownloadManager::CheckIfSuggestedPathExists( |
336 const FilePath& default_path) { | 355 int32 download_id, |
| 356 DownloadItem::DownloadStateInfo state, |
| 357 const FilePath& default_path) { |
337 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 358 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
338 DCHECK(info); | |
339 | 359 |
340 // Make sure the default download directory exists. | 360 // Make sure the default download directory exists. |
341 // TODO(phajdan.jr): only create the directory when we're sure the user | 361 // TODO(phajdan.jr): only create the directory when we're sure the user |
342 // is going to save there and not to another directory of his choice. | 362 // is going to save there and not to another directory of his choice. |
343 file_util::CreateDirectory(default_path); | 363 file_util::CreateDirectory(default_path); |
344 | 364 |
345 // Check writability of the suggested path. If we can't write to it, default | 365 // Check writability of the suggested path. If we can't write to it, default |
346 // to the user's "My Documents" directory. We'll prompt them in this case. | 366 // to the user's "My Documents" directory. We'll prompt them in this case. |
347 FilePath dir = info->suggested_path.DirName(); | 367 FilePath dir = state.suggested_path.DirName(); |
348 FilePath filename = info->suggested_path.BaseName(); | 368 FilePath filename = state.suggested_path.BaseName(); |
349 if (!file_util::PathIsWritable(dir)) { | 369 if (!file_util::PathIsWritable(dir)) { |
350 VLOG(1) << "Unable to write to directory \"" << dir.value() << "\""; | 370 VLOG(1) << "Unable to write to directory \"" << dir.value() << "\""; |
351 info->prompt_user_for_save_location = true; | 371 state.prompt_user_for_save_location = true; |
352 PathService::Get(chrome::DIR_USER_DOCUMENTS, &info->suggested_path); | 372 PathService::Get(chrome::DIR_USER_DOCUMENTS, &state.suggested_path); |
353 info->suggested_path = info->suggested_path.Append(filename); | 373 state.suggested_path = state.suggested_path.Append(filename); |
354 } | 374 } |
355 | 375 |
356 // If the download is deemed dangerous, we'll use a temporary name for it. | 376 // If the download is deemed dangerous, we'll use a temporary name for it. |
357 if (info->IsDangerous()) { | 377 if (state.IsDangerous()) { |
358 info->original_name = FilePath(info->suggested_path).BaseName(); | 378 state.target_name = FilePath(state.suggested_path).BaseName(); |
359 // Create a temporary file to hold the file until the user approves its | 379 // Create a temporary file to hold the file until the user approves its |
360 // download. | 380 // download. |
361 FilePath::StringType file_name; | 381 FilePath::StringType file_name; |
362 FilePath path; | 382 FilePath path; |
363 #if defined(OS_WIN) | 383 #if defined(OS_WIN) |
364 string16 unconfirmed_prefix = | 384 string16 unconfirmed_prefix = |
365 l10n_util::GetStringUTF16(IDS_DOWNLOAD_UNCONFIRMED_PREFIX); | 385 l10n_util::GetStringUTF16(IDS_DOWNLOAD_UNCONFIRMED_PREFIX); |
366 #else | 386 #else |
367 std::string unconfirmed_prefix = | 387 std::string unconfirmed_prefix = |
368 l10n_util::GetStringUTF8(IDS_DOWNLOAD_UNCONFIRMED_PREFIX); | 388 l10n_util::GetStringUTF8(IDS_DOWNLOAD_UNCONFIRMED_PREFIX); |
369 #endif | 389 #endif |
370 | 390 |
371 while (path.empty()) { | 391 while (path.empty()) { |
372 base::SStringPrintf( | 392 base::SStringPrintf( |
373 &file_name, | 393 &file_name, |
374 unconfirmed_prefix.append( | 394 unconfirmed_prefix.append( |
375 FILE_PATH_LITERAL(" %d.crdownload")).c_str(), | 395 FILE_PATH_LITERAL(" %d.crdownload")).c_str(), |
376 base::RandInt(0, 100000)); | 396 base::RandInt(0, 100000)); |
377 path = dir.Append(file_name); | 397 path = dir.Append(file_name); |
378 if (file_util::PathExists(path)) | 398 if (file_util::PathExists(path)) |
379 path = FilePath(); | 399 path = FilePath(); |
380 } | 400 } |
381 info->suggested_path = path; | 401 state.suggested_path = path; |
382 } else { | 402 } else { |
383 // Do not add the path uniquifier if we are saving to a specific path as in | 403 // Do not add the path uniquifier if we are saving to a specific path as in |
384 // the drag-out case. | 404 // the drag-out case. |
385 if (info->save_info.file_path.empty()) { | 405 if (state.force_file_name.empty()) { |
386 info->path_uniquifier = download_util::GetUniquePathNumberWithCrDownload( | 406 state.path_uniquifier = download_util::GetUniquePathNumberWithCrDownload( |
387 info->suggested_path); | 407 state.suggested_path); |
388 } | 408 } |
389 // We know the final path, build it if necessary. | 409 // We know the final path, build it if necessary. |
390 if (info->path_uniquifier > 0) { | 410 if (state.path_uniquifier > 0) { |
391 download_util::AppendNumberToPath(&(info->suggested_path), | 411 download_util::AppendNumberToPath(&(state.suggested_path), |
392 info->path_uniquifier); | 412 state.path_uniquifier); |
393 // Setting path_uniquifier to 0 to make sure we don't try to unique it | 413 // Setting path_uniquifier to 0 to make sure we don't try to unique it |
394 // later on. | 414 // later on. |
395 info->path_uniquifier = 0; | 415 state.path_uniquifier = 0; |
396 } else if (info->path_uniquifier == -1) { | 416 } else if (state.path_uniquifier == -1) { |
397 // We failed to find a unique path. We have to prompt the user. | 417 // We failed to find a unique path. We have to prompt the user. |
398 VLOG(1) << "Unable to find a unique path for suggested path \"" | 418 VLOG(1) << "Unable to find a unique path for suggested path \"" |
399 << info->suggested_path.value() << "\""; | 419 << state.suggested_path.value() << "\""; |
400 info->prompt_user_for_save_location = true; | 420 state.prompt_user_for_save_location = true; |
401 } | 421 } |
402 } | 422 } |
403 | 423 |
404 // Create an empty file at the suggested path so that we don't allocate the | 424 // Create an empty file at the suggested path so that we don't allocate the |
405 // same "non-existant" path to multiple downloads. | 425 // same "non-existant" path to multiple downloads. |
406 // See: http://code.google.com/p/chromium/issues/detail?id=3662 | 426 // See: http://code.google.com/p/chromium/issues/detail?id=3662 |
407 if (!info->prompt_user_for_save_location && | 427 if (!state.prompt_user_for_save_location && |
408 info->save_info.file_path.empty()) { | 428 state.force_file_name.empty()) { |
409 if (info->IsDangerous()) | 429 if (state.IsDangerous()) |
410 file_util::WriteFile(info->suggested_path, "", 0); | 430 file_util::WriteFile(state.suggested_path, "", 0); |
411 else | 431 else |
412 file_util::WriteFile(download_util::GetCrDownloadPath( | 432 file_util::WriteFile(download_util::GetCrDownloadPath( |
413 info->suggested_path), "", 0); | 433 state.suggested_path), "", 0); |
414 } | 434 } |
415 | 435 |
416 BrowserThread::PostTask( | 436 BrowserThread::PostTask( |
417 BrowserThread::UI, FROM_HERE, | 437 BrowserThread::UI, FROM_HERE, |
418 NewRunnableMethod(this, | 438 NewRunnableMethod(this, |
419 &DownloadManager::OnPathExistenceAvailable, | 439 &DownloadManager::OnPathExistenceAvailable, |
420 info)); | 440 download_id, |
| 441 state)); |
421 } | 442 } |
422 | 443 |
423 void DownloadManager::OnPathExistenceAvailable(DownloadCreateInfo* info) { | 444 void DownloadManager::OnPathExistenceAvailable( |
424 VLOG(20) << __FUNCTION__ << "()" << " info = " << info->DebugString(); | 445 int32 download_id, DownloadItem::DownloadStateInfo new_state) { |
425 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 446 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
426 DCHECK(info); | |
427 | 447 |
428 if (info->prompt_user_for_save_location) { | 448 DownloadItem* download = GetActiveDownloadItem(download_id); |
| 449 if (!download) |
| 450 return; |
| 451 |
| 452 VLOG(20) << __FUNCTION__ << "()" |
| 453 << " download = " << download->DebugString(true); |
| 454 |
| 455 download->SetFileCheckResults(new_state); |
| 456 |
| 457 DownloadItem::DownloadStateInfo state(*download); |
| 458 |
| 459 if (state.prompt_user_for_save_location) { |
429 // We must ask the user for the place to put the download. | 460 // We must ask the user for the place to put the download. |
430 if (!select_file_dialog_.get()) | 461 if (!select_file_dialog_.get()) |
431 select_file_dialog_ = SelectFileDialog::Create(this); | 462 select_file_dialog_ = SelectFileDialog::Create(this); |
432 | 463 |
433 TabContents* contents = info->process_handle.GetTabContents(); | 464 DownloadProcessHandle process_handle = download->process_handle(); |
| 465 TabContents* contents = process_handle.GetTabContents(); |
434 SelectFileDialog::FileTypeInfo file_type_info; | 466 SelectFileDialog::FileTypeInfo file_type_info; |
435 FilePath::StringType extension = info->suggested_path.Extension(); | 467 FilePath::StringType extension = state.suggested_path.Extension(); |
436 if (!extension.empty()) { | 468 if (!extension.empty()) { |
437 extension.erase(extension.begin()); // drop the . | 469 extension.erase(extension.begin()); // drop the . |
438 file_type_info.extensions.resize(1); | 470 file_type_info.extensions.resize(1); |
439 file_type_info.extensions[0].push_back(extension); | 471 file_type_info.extensions[0].push_back(extension); |
440 } | 472 } |
441 file_type_info.include_all_files = true; | 473 file_type_info.include_all_files = true; |
442 gfx::NativeWindow owning_window = | 474 gfx::NativeWindow owning_window = |
443 contents ? platform_util::GetTopLevel(contents->GetNativeView()) : NULL; | 475 contents ? platform_util::GetTopLevel(contents->GetNativeView()) : NULL; |
| 476 // |id_ptr| will be deleted in either FileSelected() or |
| 477 // FileSelectionCancelled(). |
| 478 int32* id_ptr = new int32; |
| 479 *id_ptr = download_id; |
444 select_file_dialog_->SelectFile(SelectFileDialog::SELECT_SAVEAS_FILE, | 480 select_file_dialog_->SelectFile(SelectFileDialog::SELECT_SAVEAS_FILE, |
445 string16(), | 481 string16(), |
446 info->suggested_path, | 482 state.suggested_path, |
447 &file_type_info, 0, FILE_PATH_LITERAL(""), | 483 &file_type_info, 0, FILE_PATH_LITERAL(""), |
448 contents, owning_window, info); | 484 contents, owning_window, |
| 485 reinterpret_cast<void *>(id_ptr)); |
449 FOR_EACH_OBSERVER(Observer, observers_, | 486 FOR_EACH_OBSERVER(Observer, observers_, |
450 SelectFileDialogDisplayed(info->download_id)); | 487 SelectFileDialogDisplayed(download_id)); |
451 } else { | 488 } else { |
452 // No prompting for download, just continue with the suggested name. | 489 // No prompting for download, just continue with the suggested name. |
453 info->path = info->suggested_path; | 490 ContinueDownloadWithPath(download_id, state.suggested_path); |
454 AttachDownloadItem(info); | |
455 } | 491 } |
456 } | 492 } |
457 | 493 |
458 void DownloadManager::CreateDownloadItem(DownloadCreateInfo* info) { | 494 void DownloadManager::CreateDownloadItem(DownloadCreateInfo* info) { |
459 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 495 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
460 | 496 |
461 DownloadItem* download = new DownloadItem(this, *info, | 497 DownloadItem* download = new DownloadItem(this, *info, |
462 profile_->IsOffTheRecord()); | 498 profile_->IsOffTheRecord()); |
463 DCHECK(!ContainsKey(in_progress_, info->download_id)); | 499 int32 download_id = info->download_id; |
464 DCHECK(!ContainsKey(active_downloads_, info->download_id)); | 500 DCHECK(!ContainsKey(in_progress_, download_id)); |
| 501 DCHECK(!ContainsKey(active_downloads_, download_id)); |
465 downloads_.insert(download); | 502 downloads_.insert(download); |
466 active_downloads_[info->download_id] = download; | 503 active_downloads_[download_id] = download; |
467 } | 504 } |
468 | 505 |
469 void DownloadManager::AttachDownloadItem(DownloadCreateInfo* info) { | 506 void DownloadManager::ContinueDownloadWithPath(int32 download_id, |
470 VLOG(20) << __FUNCTION__ << "()" << " info = " << info->DebugString(); | 507 const FilePath& chosen_file) { |
471 | |
472 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 508 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
473 | 509 |
474 // Life of |info| ends here. No more references to it after this method. | |
475 scoped_ptr<DownloadCreateInfo> infop(info); | |
476 | |
477 // NOTE(ahendrickson) Eventually |active_downloads_| will replace | 510 // NOTE(ahendrickson) Eventually |active_downloads_| will replace |
478 // |in_progress_|, but we don't want to change the semantics yet. | 511 // |in_progress_|, but we don't want to change the semantics yet. |
479 DCHECK(!ContainsKey(in_progress_, info->download_id)); | 512 DCHECK(!ContainsKey(in_progress_, download_id)); |
480 DCHECK(ContainsKey(active_downloads_, info->download_id)); | 513 DownloadItem* download = GetActiveDownloadItem(download_id); |
481 DownloadItem* download = active_downloads_[info->download_id]; | |
482 DCHECK(download != NULL); | |
483 DCHECK(ContainsKey(downloads_, download)); | 514 DCHECK(ContainsKey(downloads_, download)); |
| 515 if (!download) |
| 516 return; |
484 | 517 |
485 download->SetFileCheckResults(info->path, | 518 // Make sure the initial file name is set only once. |
486 info->is_dangerous_file, | 519 DCHECK(download->full_path().empty()); |
487 info->is_dangerous_url, | 520 download->set_path(chosen_file); |
488 info->path_uniquifier, | 521 download->UpdateTarget(); |
489 info->prompt_user_for_save_location, | 522 |
490 info->is_extension_install, | 523 VLOG(20) << __FUNCTION__ << "()" |
491 info->original_name); | 524 << " download = " << download->DebugString(true); |
492 in_progress_[info->download_id] = download; | 525 |
| 526 in_progress_[download_id] = download; |
493 UpdateAppIcon(); // Reflect entry into in_progress_. | 527 UpdateAppIcon(); // Reflect entry into in_progress_. |
494 | 528 |
495 // Rename to intermediate name. | 529 // Rename to intermediate name. |
496 FilePath download_path; | 530 FilePath download_path; |
497 if (info->IsDangerous()) { | 531 if (download->IsDangerous()) { |
498 // The download is not safe. We can now rename the file to its | 532 // The download is not safe. We can now rename the file to its |
499 // tentative name using RenameInProgressDownloadFile. | 533 // tentative name using RenameInProgressDownloadFile. |
500 // NOTE: The |Rename| below will be a no-op for dangerous files, as we're | 534 // NOTE: The |Rename| below will be a no-op for dangerous files, as we're |
501 // renaming it to the same name. | 535 // renaming it to the same name. |
502 download_path = info->path; | 536 download_path = download->full_path(); |
503 } else { | 537 } else { |
504 // The download is a safe download. We need to | 538 // The download is a safe download. We need to |
505 // rename it to its intermediate '.crdownload' path. The final | 539 // rename it to its intermediate '.crdownload' path. The final |
506 // name after user confirmation will be set from | 540 // name after user confirmation will be set from |
507 // DownloadItem::OnDownloadCompleting. | 541 // DownloadItem::OnDownloadCompleting. |
508 download_path = download_util::GetCrDownloadPath(info->path); | 542 download_path = |
| 543 download_util::GetCrDownloadPath(download->full_path()); |
509 } | 544 } |
510 | 545 |
511 BrowserThread::PostTask( | 546 BrowserThread::PostTask( |
512 BrowserThread::FILE, FROM_HERE, | 547 BrowserThread::FILE, FROM_HERE, |
513 NewRunnableMethod( | 548 NewRunnableMethod( |
514 file_manager_, &DownloadFileManager::RenameInProgressDownloadFile, | 549 file_manager_, &DownloadFileManager::RenameInProgressDownloadFile, |
515 download->id(), download_path)); | 550 download->id(), download_path)); |
516 | 551 |
517 download->Rename(download_path); | 552 download->Rename(download_path); |
518 | 553 |
519 download_history_->AddEntry(*info, download, | 554 download_history_->AddEntry(download, |
520 NewCallback(this, &DownloadManager::OnCreateDownloadEntryComplete)); | 555 NewCallback(this, &DownloadManager::OnCreateDownloadEntryComplete)); |
521 } | 556 } |
522 | 557 |
523 void DownloadManager::UpdateDownload(int32 download_id, int64 size) { | 558 void DownloadManager::UpdateDownload(int32 download_id, int64 size) { |
524 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 559 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
525 DownloadMap::iterator it = active_downloads_.find(download_id); | 560 DownloadMap::iterator it = active_downloads_.find(download_id); |
526 if (it != active_downloads_.end()) { | 561 if (it != active_downloads_.end()) { |
527 DownloadItem* download = it->second; | 562 DownloadItem* download = it->second; |
528 if (download->IsInProgress()) { | 563 if (download->IsInProgress()) { |
529 download->Update(size); | 564 download->Update(size); |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
723 int os_error) { | 758 int os_error) { |
724 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 759 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
725 DownloadMap::iterator it = active_downloads_.find(download_id); | 760 DownloadMap::iterator it = active_downloads_.find(download_id); |
726 // A cancel at the right time could remove the download from the | 761 // A cancel at the right time could remove the download from the |
727 // |active_downloads_| map before we get here. | 762 // |active_downloads_| map before we get here. |
728 if (it == active_downloads_.end()) | 763 if (it == active_downloads_.end()) |
729 return; | 764 return; |
730 | 765 |
731 DownloadItem* download = it->second; | 766 DownloadItem* download = it->second; |
732 | 767 |
733 VLOG(20) << "Error " << os_error << " at offset " | 768 VLOG(20) << __FUNCTION__ << "()" << " Error " << os_error |
734 << download->received_bytes() << " for download = " | 769 << " at offset " << download->received_bytes() |
735 << download->DebugString(true); | 770 << " for download = " << download->DebugString(true); |
| 771 |
| 772 download->Interrupted(size, os_error); |
736 | 773 |
737 // TODO(ahendrickson) - Remove this when we add resuming of interrupted | 774 // TODO(ahendrickson) - Remove this when we add resuming of interrupted |
738 // downloads, as we will keep the download item around in that case. | 775 // downloads, as we will keep the download item around in that case. |
739 // | 776 // |
740 // Clean up will happen when the history system create callback runs if we | 777 // Clean up will happen when the history system create callback runs if we |
741 // don't have a valid db_handle yet. | 778 // don't have a valid db_handle yet. |
742 if (download->db_handle() != DownloadHistory::kUninitializedHandle) { | 779 if (download->db_handle() != DownloadHistory::kUninitializedHandle) { |
743 in_progress_.erase(download_id); | 780 in_progress_.erase(download_id); |
744 active_downloads_.erase(download_id); | 781 active_downloads_.erase(download_id); |
745 UpdateAppIcon(); // Reflect removal from in_progress_. | 782 UpdateAppIcon(); // Reflect removal from in_progress_. |
746 download_history_->UpdateEntry(download); | 783 download_history_->UpdateEntry(download); |
747 } | 784 } |
748 | 785 |
749 download->Interrupted(size, os_error); | |
750 | |
751 BrowserThread::PostTask( | 786 BrowserThread::PostTask( |
752 BrowserThread::FILE, FROM_HERE, | 787 BrowserThread::FILE, FROM_HERE, |
753 NewRunnableMethod( | 788 NewRunnableMethod( |
754 file_manager_, &DownloadFileManager::CancelDownload, download_id)); | 789 file_manager_, &DownloadFileManager::CancelDownload, download_id)); |
755 } | 790 } |
756 | 791 |
757 void DownloadManager::PauseDownload(int32 download_id, bool pause) { | 792 void DownloadManager::PauseDownload(int32 download_id, bool pause) { |
758 DownloadMap::iterator it = in_progress_.find(download_id); | 793 DownloadMap::iterator it = in_progress_.find(download_id); |
759 if (it == in_progress_.end()) | 794 if (it == in_progress_.end()) |
760 return; | 795 return; |
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
957 int64 total_bytes = 0; | 992 int64 total_bytes = 0; |
958 for (DownloadMap::iterator i = in_progress_.begin(); | 993 for (DownloadMap::iterator i = in_progress_.begin(); |
959 i != in_progress_.end(); ++i) { | 994 i != in_progress_.end(); ++i) { |
960 total_bytes += i->second->total_bytes(); | 995 total_bytes += i->second->total_bytes(); |
961 } | 996 } |
962 return total_bytes; | 997 return total_bytes; |
963 } | 998 } |
964 | 999 |
965 void DownloadManager::FileSelected(const FilePath& path, | 1000 void DownloadManager::FileSelected(const FilePath& path, |
966 int index, void* params) { | 1001 int index, void* params) { |
967 DownloadCreateInfo* info = reinterpret_cast<DownloadCreateInfo*>(params); | 1002 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
968 if (info->prompt_user_for_save_location) | 1003 |
| 1004 int32* id_ptr = reinterpret_cast<int32 *>(params); |
| 1005 DCHECK(id_ptr != NULL); |
| 1006 int32 download_id = *id_ptr; |
| 1007 delete id_ptr; |
| 1008 DCHECK_EQ(index, download_id); |
| 1009 |
| 1010 DownloadItem* download = GetActiveDownloadItem(download_id); |
| 1011 if (!download) |
| 1012 return; |
| 1013 VLOG(20) << __FUNCTION__ << "()" << " path = \"" << path.value() << "\"" |
| 1014 << " download = " << download->DebugString(true); |
| 1015 |
| 1016 if (download->save_as()) |
969 last_download_path_ = path.DirName(); | 1017 last_download_path_ = path.DirName(); |
970 | 1018 |
971 info->path = path; | 1019 // Make sure the initial file name is set only once. |
972 AttachDownloadItem(info); | 1020 ContinueDownloadWithPath(download_id, path); |
973 } | 1021 } |
974 | 1022 |
975 void DownloadManager::FileSelectionCanceled(void* params) { | 1023 void DownloadManager::FileSelectionCanceled(void* params) { |
976 // The user didn't pick a place to save the file, so need to cancel the | 1024 // The user didn't pick a place to save the file, so need to cancel the |
977 // download that's already in progress to the temporary location. | 1025 // download that's already in progress to the temporary location. |
978 DownloadCreateInfo* info = reinterpret_cast<DownloadCreateInfo*>(params); | 1026 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
979 DownloadCancelledInternal(info->download_id, info->process_handle); | 1027 int32* id_ptr = reinterpret_cast<int32 *>(params); |
| 1028 DCHECK(id_ptr != NULL); |
| 1029 int32 download_id = *id_ptr; |
| 1030 delete id_ptr; |
| 1031 |
| 1032 DownloadItem* download = GetActiveDownloadItem(download_id); |
| 1033 if (!download) |
| 1034 return; |
| 1035 |
| 1036 VLOG(20) << __FUNCTION__ << "()" |
| 1037 << " download = " << download->DebugString(true); |
| 1038 |
| 1039 DownloadCancelledInternal(download_id, download->process_handle()); |
980 } | 1040 } |
981 | 1041 |
982 void DownloadManager::DangerousDownloadValidated(DownloadItem* download) { | 1042 void DownloadManager::DangerousDownloadValidated(DownloadItem* download) { |
983 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1043 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
984 DCHECK_EQ(DownloadItem::DANGEROUS, download->safety_state()); | 1044 DCHECK_EQ(DownloadItem::DANGEROUS, download->safety_state()); |
985 download->set_safety_state(DownloadItem::DANGEROUS_BUT_VALIDATED); | 1045 download->set_safety_state(DownloadItem::DANGEROUS_BUT_VALIDATED); |
986 download->UpdateObservers(); | 1046 download->UpdateObservers(); |
987 | 1047 |
988 MaybeCompleteDownload(download); | 1048 MaybeCompleteDownload(download); |
989 } | 1049 } |
990 | 1050 |
991 // Operations posted to us from the history service ---------------------------- | 1051 // Operations posted to us from the history service ---------------------------- |
992 | 1052 |
993 // The history service has retrieved all download entries. 'entries' contains | 1053 // The history service has retrieved all download entries. 'entries' contains |
994 // 'DownloadCreateInfo's in sorted order (by ascending start_time). | 1054 // 'DownloadHistoryInfo's in sorted order (by ascending start_time). |
995 void DownloadManager::OnQueryDownloadEntriesComplete( | 1055 void DownloadManager::OnQueryDownloadEntriesComplete( |
996 std::vector<DownloadCreateInfo>* entries) { | 1056 std::vector<DownloadHistoryInfo>* entries) { |
997 for (size_t i = 0; i < entries->size(); ++i) { | 1057 for (size_t i = 0; i < entries->size(); ++i) { |
998 DownloadItem* download = new DownloadItem(this, entries->at(i)); | 1058 DownloadItem* download = new DownloadItem(this, entries->at(i)); |
999 DCHECK(!ContainsKey(history_downloads_, download->db_handle())); | 1059 DCHECK(!ContainsKey(history_downloads_, download->db_handle())); |
1000 downloads_.insert(download); | 1060 downloads_.insert(download); |
1001 history_downloads_[download->db_handle()] = download; | 1061 history_downloads_[download->db_handle()] = download; |
1002 VLOG(20) << __FUNCTION__ << "()" << i << ">" | 1062 VLOG(20) << __FUNCTION__ << "()" << i << ">" |
1003 << " download = " << download->DebugString(true); | 1063 << " download = " << download->DebugString(true); |
1004 } | 1064 } |
1005 NotifyModelChanged(); | 1065 NotifyModelChanged(); |
1006 } | 1066 } |
1007 | 1067 |
1008 // Once the new DownloadItem's creation info has been committed to the history | 1068 // Once the new DownloadItem's creation info has been committed to the history |
1009 // service, we associate the DownloadItem with the db handle, update our | 1069 // service, we associate the DownloadItem with the db handle, update our |
1010 // 'history_downloads_' map and inform observers. | 1070 // 'history_downloads_' map and inform observers. |
1011 void DownloadManager::OnCreateDownloadEntryComplete( | 1071 void DownloadManager::OnCreateDownloadEntryComplete(int32 download_id, |
1012 DownloadCreateInfo info, | 1072 int64 db_handle) { |
1013 int64 db_handle) { | |
1014 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1073 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1015 DownloadMap::iterator it = in_progress_.find(info.download_id); | 1074 DownloadItem* download = GetActiveDownloadItem(download_id); |
1016 DCHECK(it != in_progress_.end()); | 1075 if (!download) |
| 1076 return; |
1017 | 1077 |
1018 DownloadItem* download = it->second; | |
1019 VLOG(20) << __FUNCTION__ << "()" << " db_handle = " << db_handle | 1078 VLOG(20) << __FUNCTION__ << "()" << " db_handle = " << db_handle |
1020 << " download_id = " << info.download_id | 1079 << " download_id = " << download_id |
1021 << " download = " << download->DebugString(true); | 1080 << " download = " << download->DebugString(true); |
1022 | 1081 |
1023 // It's not immediately obvious, but HistoryBackend::CreateDownload() can | 1082 // It's not immediately obvious, but HistoryBackend::CreateDownload() can |
1024 // call this function with an invalid |db_handle|. For instance, this can | 1083 // call this function with an invalid |db_handle|. For instance, this can |
1025 // happen when the history database is offline. We cannot have multiple | 1084 // happen when the history database is offline. We cannot have multiple |
1026 // DownloadItems with the same invalid db_handle, so we need to assign a | 1085 // DownloadItems with the same invalid db_handle, so we need to assign a |
1027 // unique |db_handle| here. | 1086 // unique |db_handle| here. |
1028 if (db_handle == DownloadHistory::kUninitializedHandle) | 1087 if (db_handle == DownloadHistory::kUninitializedHandle) |
1029 db_handle = download_history_->GetNextFakeDbHandle(); | 1088 db_handle = download_history_->GetNextFakeDbHandle(); |
1030 | 1089 |
1031 DCHECK(download->db_handle() == DownloadHistory::kUninitializedHandle); | 1090 DCHECK(download->db_handle() == DownloadHistory::kUninitializedHandle); |
1032 download->set_db_handle(db_handle); | 1091 download->set_db_handle(db_handle); |
1033 | 1092 |
1034 DCHECK(!ContainsKey(history_downloads_, download->db_handle())); | 1093 DCHECK(!ContainsKey(history_downloads_, download->db_handle())); |
1035 history_downloads_[download->db_handle()] = download; | 1094 history_downloads_[download->db_handle()] = download; |
1036 | 1095 |
1037 // Show in the appropriate browser UI. | 1096 // Show in the appropriate browser UI. |
1038 // This includes buttons to save or cancel, for a dangerous download. | 1097 // This includes buttons to save or cancel, for a dangerous download. |
1039 ShowDownloadInBrowser(&info.process_handle, download); | 1098 ShowDownloadInBrowser(download); |
1040 | 1099 |
1041 // Inform interested objects about the new download. | 1100 // Inform interested objects about the new download. |
1042 NotifyModelChanged(); | 1101 NotifyModelChanged(); |
1043 | 1102 |
1044 // If the download is still in progress, try to complete it. | 1103 // If the download is still in progress, try to complete it. |
1045 // | 1104 // |
1046 // Otherwise, download has been cancelled or interrupted before we've | 1105 // Otherwise, download has been cancelled or interrupted before we've |
1047 // received the DB handle. We post one final message to the history | 1106 // received the DB handle. We post one final message to the history |
1048 // service so that it can be properly in sync with the DownloadItem's | 1107 // service so that it can be properly in sync with the DownloadItem's |
1049 // completion status, and also inform any observers so that they get | 1108 // completion status, and also inform any observers so that they get |
1050 // more than just the start notification. | 1109 // more than just the start notification. |
1051 if (download->IsInProgress()) { | 1110 if (download->IsInProgress()) { |
1052 MaybeCompleteDownload(download); | 1111 MaybeCompleteDownload(download); |
1053 } else { | 1112 } else { |
1054 DCHECK(download->IsCancelled()) | 1113 DCHECK(download->IsCancelled()) |
1055 << " download = " << download->DebugString(true); | 1114 << " download = " << download->DebugString(true); |
1056 in_progress_.erase(it); | 1115 in_progress_.erase(download_id); |
1057 active_downloads_.erase(info.download_id); | 1116 active_downloads_.erase(download_id); |
1058 download_history_->UpdateEntry(download); | 1117 download_history_->UpdateEntry(download); |
1059 download->UpdateObservers(); | 1118 download->UpdateObservers(); |
1060 } | 1119 } |
1061 } | 1120 } |
1062 | 1121 |
1063 void DownloadManager::ShowDownloadInBrowser( | 1122 void DownloadManager::ShowDownloadInBrowser(DownloadItem* download) { |
1064 DownloadProcessHandle* process_handle, DownloadItem* download) { | |
1065 if (!process_handle) | |
1066 return; | |
1067 | 1123 |
1068 // The 'contents' may no longer exist if the user closed the tab before we | 1124 // The 'contents' may no longer exist if the user closed the tab before we |
1069 // get this start completion event. If it does, tell the origin TabContents | 1125 // get this start completion event. If it does, tell the origin TabContents |
1070 // to display its download shelf. | 1126 // to display its download shelf. |
1071 TabContents* contents = process_handle->GetTabContents(); | 1127 DownloadProcessHandle process_handle = download->process_handle(); |
| 1128 TabContents* contents = process_handle.GetTabContents(); |
1072 | 1129 |
1073 // If the contents no longer exists, we start the download in the last active | 1130 // If the contents no longer exists, we start the download in the last active |
1074 // browser. This is not ideal but better than fully hiding the download from | 1131 // browser. This is not ideal but better than fully hiding the download from |
1075 // the user. | 1132 // the user. |
1076 if (!contents) { | 1133 if (!contents) { |
1077 Browser* last_active = BrowserList::GetLastActive(); | 1134 Browser* last_active = BrowserList::GetLastActive(); |
1078 if (last_active) | 1135 if (last_active) |
1079 contents = last_active->GetSelectedTabContents(); | 1136 contents = last_active->GetSelectedTabContents(); |
1080 } | 1137 } |
1081 | 1138 |
1082 if (!contents) | 1139 if (!contents) |
1083 return; | 1140 return; |
1084 | 1141 |
1085 contents->OnStartDownload(download); | 1142 contents->OnStartDownload(download); |
1086 } | 1143 } |
1087 | 1144 |
1088 // Clears the last download path, used to initialize "save as" dialogs. | 1145 // Clears the last download path, used to initialize "save as" dialogs. |
1089 void DownloadManager::ClearLastDownloadPath() { | 1146 void DownloadManager::ClearLastDownloadPath() { |
1090 last_download_path_ = FilePath(); | 1147 last_download_path_ = FilePath(); |
1091 } | 1148 } |
1092 | 1149 |
1093 void DownloadManager::NotifyModelChanged() { | 1150 void DownloadManager::NotifyModelChanged() { |
1094 FOR_EACH_OBSERVER(Observer, observers_, ModelChanged()); | 1151 FOR_EACH_OBSERVER(Observer, observers_, ModelChanged()); |
1095 } | 1152 } |
1096 | 1153 |
1097 DownloadItem* DownloadManager::GetDownloadItem(int id) { | 1154 DownloadItem* DownloadManager::GetDownloadItem(int download_id) { |
1098 for (DownloadMap::iterator it = history_downloads_.begin(); | 1155 for (DownloadMap::iterator it = history_downloads_.begin(); |
1099 it != history_downloads_.end(); ++it) { | 1156 it != history_downloads_.end(); ++it) { |
1100 DownloadItem* item = it->second; | 1157 DownloadItem* item = it->second; |
1101 if (item->id() == id) | 1158 if (item->id() == download_id) |
1102 return item; | 1159 return item; |
1103 } | 1160 } |
1104 return NULL; | 1161 return NULL; |
1105 } | 1162 } |
1106 | 1163 |
| 1164 DownloadItem* DownloadManager::GetActiveDownloadItem(int download_id) { |
| 1165 DCHECK(ContainsKey(active_downloads_, download_id)); |
| 1166 DownloadItem* download = active_downloads_[download_id]; |
| 1167 DCHECK(download != NULL); |
| 1168 return download; |
| 1169 } |
| 1170 |
1107 // Confirm that everything in all maps is also in |downloads_|, and that | 1171 // Confirm that everything in all maps is also in |downloads_|, and that |
1108 // everything in |downloads_| is also in some other map. | 1172 // everything in |downloads_| is also in some other map. |
1109 void DownloadManager::AssertContainersConsistent() const { | 1173 void DownloadManager::AssertContainersConsistent() const { |
1110 #if !defined(NDEBUG) | 1174 #if !defined(NDEBUG) |
1111 // Turn everything into sets. | 1175 // Turn everything into sets. |
1112 DownloadSet active_set, history_set; | 1176 DownloadSet active_set, history_set; |
1113 const DownloadMap* input_maps[] = {&active_downloads_, &history_downloads_}; | 1177 const DownloadMap* input_maps[] = {&active_downloads_, &history_downloads_}; |
1114 DownloadSet* local_sets[] = {&active_set, &history_set}; | 1178 DownloadSet* local_sets[] = {&active_set, &history_set}; |
1115 DCHECK_EQ(ARRAYSIZE_UNSAFE(input_maps), ARRAYSIZE_UNSAFE(local_sets)); | 1179 DCHECK_EQ(ARRAYSIZE_UNSAFE(input_maps), ARRAYSIZE_UNSAFE(local_sets)); |
1116 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(input_maps); i++) { | 1180 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(input_maps); i++) { |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1170 observed_download_manager_->RemoveObserver(this); | 1234 observed_download_manager_->RemoveObserver(this); |
1171 } | 1235 } |
1172 | 1236 |
1173 void DownloadManager::OtherDownloadManagerObserver::ModelChanged() { | 1237 void DownloadManager::OtherDownloadManagerObserver::ModelChanged() { |
1174 observing_download_manager_->NotifyModelChanged(); | 1238 observing_download_manager_->NotifyModelChanged(); |
1175 } | 1239 } |
1176 | 1240 |
1177 void DownloadManager::OtherDownloadManagerObserver::ManagerGoingDown() { | 1241 void DownloadManager::OtherDownloadManagerObserver::ManagerGoingDown() { |
1178 observed_download_manager_ = NULL; | 1242 observed_download_manager_ = NULL; |
1179 } | 1243 } |
OLD | NEW |