| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/file_select_helper.h" | 5 #include "chrome/browser/file_select_helper.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 369 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 380 return file_type.Pass(); | 380 return file_type.Pass(); |
| 381 } | 381 } |
| 382 | 382 |
| 383 // static | 383 // static |
| 384 void FileSelectHelper::RunFileChooser(content::WebContents* tab, | 384 void FileSelectHelper::RunFileChooser(content::WebContents* tab, |
| 385 const FileChooserParams& params) { | 385 const FileChooserParams& params) { |
| 386 Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext()); | 386 Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext()); |
| 387 // FileSelectHelper will keep itself alive until it sends the result message. | 387 // FileSelectHelper will keep itself alive until it sends the result message. |
| 388 scoped_refptr<FileSelectHelper> file_select_helper( | 388 scoped_refptr<FileSelectHelper> file_select_helper( |
| 389 new FileSelectHelper(profile)); | 389 new FileSelectHelper(profile)); |
| 390 file_select_helper->RunFileChooser(tab->GetRenderViewHost(), tab, params); | 390 file_select_helper->RunFileChooser( |
| 391 tab->GetRenderViewHost(), tab, |
| 392 make_scoped_ptr(new content::FileChooserParams(params))); |
| 391 } | 393 } |
| 392 | 394 |
| 393 // static | 395 // static |
| 394 void FileSelectHelper::EnumerateDirectory(content::WebContents* tab, | 396 void FileSelectHelper::EnumerateDirectory(content::WebContents* tab, |
| 395 int request_id, | 397 int request_id, |
| 396 const base::FilePath& path) { | 398 const base::FilePath& path) { |
| 397 Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext()); | 399 Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext()); |
| 398 // FileSelectHelper will keep itself alive until it sends the result message. | 400 // FileSelectHelper will keep itself alive until it sends the result message. |
| 399 scoped_refptr<FileSelectHelper> file_select_helper( | 401 scoped_refptr<FileSelectHelper> file_select_helper( |
| 400 new FileSelectHelper(profile)); | 402 new FileSelectHelper(profile)); |
| 401 file_select_helper->EnumerateDirectory( | 403 file_select_helper->EnumerateDirectory( |
| 402 request_id, tab->GetRenderViewHost(), path); | 404 request_id, tab->GetRenderViewHost(), path); |
| 403 } | 405 } |
| 404 | 406 |
| 405 void FileSelectHelper::RunFileChooser(RenderViewHost* render_view_host, | 407 void FileSelectHelper::RunFileChooser(RenderViewHost* render_view_host, |
| 406 content::WebContents* web_contents, | 408 content::WebContents* web_contents, |
| 407 const FileChooserParams& params) { | 409 scoped_ptr<FileChooserParams> params) { |
| 408 DCHECK(!render_view_host_); | 410 DCHECK(!render_view_host_); |
| 409 DCHECK(!web_contents_); | 411 DCHECK(!web_contents_); |
| 410 DCHECK(params.default_file_name.empty() || | 412 DCHECK(params->default_file_name.empty() || |
| 411 params.mode == FileChooserParams::Save) | 413 params->mode == FileChooserParams::Save) |
| 412 << "The default_file_name parameter should only be specified for Save " | 414 << "The default_file_name parameter should only be specified for Save " |
| 413 "file choosers"; | 415 "file choosers"; |
| 414 DCHECK(params.default_file_name == params.default_file_name.BaseName()) | 416 DCHECK(params->default_file_name == params->default_file_name.BaseName()) |
| 415 << "The default_file_name parameter should not contain path separators"; | 417 << "The default_file_name parameter should not contain path separators"; |
| 416 | 418 |
| 417 render_view_host_ = render_view_host; | 419 render_view_host_ = render_view_host; |
| 418 web_contents_ = web_contents; | 420 web_contents_ = web_contents; |
| 419 notification_registrar_.RemoveAll(); | 421 notification_registrar_.RemoveAll(); |
| 420 content::WebContentsObserver::Observe(web_contents_); | 422 content::WebContentsObserver::Observe(web_contents_); |
| 421 notification_registrar_.Add( | 423 notification_registrar_.Add( |
| 422 this, content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED, | 424 this, content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED, |
| 423 content::Source<RenderWidgetHost>(render_view_host_->GetWidget())); | 425 content::Source<RenderWidgetHost>(render_view_host_->GetWidget())); |
| 424 | 426 |
| 425 BrowserThread::PostTask( | 427 BrowserThread::PostTask( |
| 426 BrowserThread::FILE, FROM_HERE, | 428 BrowserThread::FILE, FROM_HERE, |
| 427 base::Bind(&FileSelectHelper::RunFileChooserOnFileThread, this, params)); | 429 base::Bind(&FileSelectHelper::GetFileTypesOnFileThread, this, |
| 430 base::Passed(¶ms))); |
| 428 | 431 |
| 429 // Because this class returns notifications to the RenderViewHost, it is | 432 // Because this class returns notifications to the RenderViewHost, it is |
| 430 // difficult for callers to know how long to keep a reference to this | 433 // difficult for callers to know how long to keep a reference to this |
| 431 // instance. We AddRef() here to keep the instance alive after we return | 434 // instance. We AddRef() here to keep the instance alive after we return |
| 432 // to the caller, until the last callback is received from the file dialog. | 435 // to the caller, until the last callback is received from the file dialog. |
| 433 // At that point, we must call RunFileChooserEnd(). | 436 // At that point, we must call RunFileChooserEnd(). |
| 434 AddRef(); | 437 AddRef(); |
| 435 } | 438 } |
| 436 | 439 |
| 437 void FileSelectHelper::RunFileChooserOnFileThread( | 440 void FileSelectHelper::GetFileTypesOnFileThread( |
| 438 const FileChooserParams& params) { | 441 scoped_ptr<FileChooserParams> params) { |
| 439 select_file_types_ = GetFileTypesFromAcceptType(params.accept_types); | 442 select_file_types_ = GetFileTypesFromAcceptType(params->accept_types); |
| 440 select_file_types_->support_drive = !params.need_local_path; | 443 select_file_types_->support_drive = !params->need_local_path; |
| 441 | 444 |
| 442 BrowserThread::PostTask( | 445 BrowserThread::PostTask( |
| 443 BrowserThread::UI, FROM_HERE, | 446 BrowserThread::UI, FROM_HERE, |
| 444 base::Bind(&FileSelectHelper::RunFileChooserOnUIThread, this, params)); | 447 base::Bind(&FileSelectHelper::GetSanitizedFilenameOnUIThread, this, |
| 448 base::Passed(¶ms))); |
| 445 } | 449 } |
| 446 | 450 |
| 451 void FileSelectHelper::GetSanitizedFilenameOnUIThread( |
| 452 scoped_ptr<FileChooserParams> params) { |
| 453 base::FilePath default_file_path = profile_->last_selected_directory().Append( |
| 454 GetSanitizedFileName(params->default_file_name)); |
| 455 |
| 456 #if defined(FULL_SAFE_BROWSING) |
| 457 // Note that FileChooserParams::requestor is not considered a trusted field |
| 458 // since it's provided by the renderer and not validated browserside. |
| 459 if (params->mode == FileChooserParams::Save && |
| 460 !params->default_file_name.empty()) { |
| 461 GURL requestor = params->requestor; |
| 462 safe_browsing::CheckUnverifiedDownloadPolicy( |
| 463 requestor, default_file_path, |
| 464 base::Bind(&FileSelectHelper::ApplyUnverifiedDownloadPolicy, this, |
| 465 default_file_path, base::Passed(¶ms))); |
| 466 return; |
| 467 } |
| 468 #endif |
| 469 |
| 470 RunFileChooserOnUIThread(default_file_path, params.Pass()); |
| 471 } |
| 472 |
| 473 #if defined(FULL_SAFE_BROWSING) |
| 474 void FileSelectHelper::ApplyUnverifiedDownloadPolicy( |
| 475 const base::FilePath& default_path, |
| 476 scoped_ptr<FileChooserParams> params, |
| 477 safe_browsing::UnverifiedDownloadPolicy policy) { |
| 478 DCHECK(params); |
| 479 if (policy == safe_browsing::UnverifiedDownloadPolicy::DISALLOWED) { |
| 480 NotifyRenderViewHostAndEnd(std::vector<ui::SelectedFileInfo>()); |
| 481 return; |
| 482 } |
| 483 |
| 484 RunFileChooserOnUIThread(default_path, params.Pass()); |
| 485 } |
| 486 #endif |
| 487 |
| 447 void FileSelectHelper::RunFileChooserOnUIThread( | 488 void FileSelectHelper::RunFileChooserOnUIThread( |
| 448 const FileChooserParams& params) { | 489 const base::FilePath& default_file_path, |
| 490 scoped_ptr<FileChooserParams> params) { |
| 491 DCHECK(params); |
| 449 if (!render_view_host_ || !web_contents_ || !IsValidProfile(profile_)) { | 492 if (!render_view_host_ || !web_contents_ || !IsValidProfile(profile_)) { |
| 450 // If the renderer was destroyed before we started, just cancel the | 493 // If the renderer was destroyed before we started, just cancel the |
| 451 // operation. | 494 // operation. |
| 452 RunFileChooserEnd(); | 495 RunFileChooserEnd(); |
| 453 return; | 496 return; |
| 454 } | 497 } |
| 455 | 498 |
| 456 base::FilePath default_file_path = profile_->last_selected_directory().Append( | |
| 457 GetSanitizedFileName(params.default_file_name)); | |
| 458 | |
| 459 #if defined(FULL_SAFE_BROWSING) | |
| 460 if (params.mode == FileChooserParams::Save && | |
| 461 !params.default_file_name.empty() && | |
| 462 !safe_browsing::IsUnverifiedDownloadAllowed(default_file_path)) { | |
| 463 NotifyRenderViewHostAndEnd(std::vector<ui::SelectedFileInfo>()); | |
| 464 return; | |
| 465 } | |
| 466 #endif | |
| 467 | |
| 468 select_file_dialog_ = ui::SelectFileDialog::Create( | 499 select_file_dialog_ = ui::SelectFileDialog::Create( |
| 469 this, new ChromeSelectFilePolicy(web_contents_)); | 500 this, new ChromeSelectFilePolicy(web_contents_)); |
| 470 if (!select_file_dialog_.get()) | 501 if (!select_file_dialog_.get()) |
| 471 return; | 502 return; |
| 472 | 503 |
| 473 dialog_mode_ = params.mode; | 504 dialog_mode_ = params->mode; |
| 474 switch (params.mode) { | 505 switch (params->mode) { |
| 475 case FileChooserParams::Open: | 506 case FileChooserParams::Open: |
| 476 dialog_type_ = ui::SelectFileDialog::SELECT_OPEN_FILE; | 507 dialog_type_ = ui::SelectFileDialog::SELECT_OPEN_FILE; |
| 477 break; | 508 break; |
| 478 case FileChooserParams::OpenMultiple: | 509 case FileChooserParams::OpenMultiple: |
| 479 dialog_type_ = ui::SelectFileDialog::SELECT_OPEN_MULTI_FILE; | 510 dialog_type_ = ui::SelectFileDialog::SELECT_OPEN_MULTI_FILE; |
| 480 break; | 511 break; |
| 481 case FileChooserParams::UploadFolder: | 512 case FileChooserParams::UploadFolder: |
| 482 dialog_type_ = ui::SelectFileDialog::SELECT_UPLOAD_FOLDER; | 513 dialog_type_ = ui::SelectFileDialog::SELECT_UPLOAD_FOLDER; |
| 483 break; | 514 break; |
| 484 case FileChooserParams::Save: | 515 case FileChooserParams::Save: |
| 485 dialog_type_ = ui::SelectFileDialog::SELECT_SAVEAS_FILE; | 516 dialog_type_ = ui::SelectFileDialog::SELECT_SAVEAS_FILE; |
| 486 break; | 517 break; |
| 487 default: | 518 default: |
| 488 // Prevent warning. | 519 // Prevent warning. |
| 489 dialog_type_ = ui::SelectFileDialog::SELECT_OPEN_FILE; | 520 dialog_type_ = ui::SelectFileDialog::SELECT_OPEN_FILE; |
| 490 NOTREACHED(); | 521 NOTREACHED(); |
| 491 } | 522 } |
| 492 | 523 |
| 493 gfx::NativeWindow owning_window = platform_util::GetTopLevel( | 524 gfx::NativeWindow owning_window = platform_util::GetTopLevel( |
| 494 render_view_host_->GetWidget()->GetView()->GetNativeView()); | 525 render_view_host_->GetWidget()->GetView()->GetNativeView()); |
| 495 | 526 |
| 496 #if defined(OS_ANDROID) | 527 #if defined(OS_ANDROID) |
| 497 // Android needs the original MIME types and an additional capture value. | 528 // Android needs the original MIME types and an additional capture value. |
| 498 std::pair<std::vector<base::string16>, bool> accept_types = | 529 std::pair<std::vector<base::string16>, bool> accept_types = |
| 499 std::make_pair(params.accept_types, params.capture); | 530 std::make_pair(params->accept_types, params->capture); |
| 500 #endif | 531 #endif |
| 501 | 532 |
| 502 select_file_dialog_->SelectFile( | 533 select_file_dialog_->SelectFile( |
| 503 dialog_type_, params.title, default_file_path, select_file_types_.get(), | 534 dialog_type_, params->title, default_file_path, select_file_types_.get(), |
| 504 select_file_types_.get() && !select_file_types_->extensions.empty() | 535 select_file_types_.get() && !select_file_types_->extensions.empty() |
| 505 ? 1 | 536 ? 1 |
| 506 : 0, // 1-based index of default extension to show. | 537 : 0, // 1-based index of default extension to show. |
| 507 base::FilePath::StringType(), | 538 base::FilePath::StringType(), |
| 508 owning_window, | 539 owning_window, |
| 509 #if defined(OS_ANDROID) | 540 #if defined(OS_ANDROID) |
| 510 &accept_types); | 541 &accept_types); |
| 511 #else | 542 #else |
| 512 NULL); | 543 NULL); |
| 513 #endif | 544 #endif |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 592 | 623 |
| 593 // static | 624 // static |
| 594 base::FilePath FileSelectHelper::GetSanitizedFileName( | 625 base::FilePath FileSelectHelper::GetSanitizedFileName( |
| 595 const base::FilePath& suggested_filename) { | 626 const base::FilePath& suggested_filename) { |
| 596 if (suggested_filename.empty()) | 627 if (suggested_filename.empty()) |
| 597 return base::FilePath(); | 628 return base::FilePath(); |
| 598 return net::GenerateFileName( | 629 return net::GenerateFileName( |
| 599 GURL(), std::string(), std::string(), suggested_filename.AsUTF8Unsafe(), | 630 GURL(), std::string(), std::string(), suggested_filename.AsUTF8Unsafe(), |
| 600 std::string(), l10n_util::GetStringUTF8(IDS_DEFAULT_DOWNLOAD_FILENAME)); | 631 std::string(), l10n_util::GetStringUTF8(IDS_DEFAULT_DOWNLOAD_FILENAME)); |
| 601 } | 632 } |
| OLD | NEW |