Index: chrome/browser/extensions/api/image_writer_private/write_from_url_operation.cc |
diff --git a/chrome/browser/extensions/api/image_writer_private/write_from_url_operation.cc b/chrome/browser/extensions/api/image_writer_private/write_from_url_operation.cc |
index 2e8fbd64153755244c75ce81b57be658681bb42a..5fe42e0bbadb0fb32319b4f9141ea54c01f07985 100644 |
--- a/chrome/browser/extensions/api/image_writer_private/write_from_url_operation.cc |
+++ b/chrome/browser/extensions/api/image_writer_private/write_from_url_operation.cc |
@@ -3,11 +3,17 @@ |
// found in the LICENSE file. |
#include "base/file_util.h" |
+#include "base/threading/worker_pool.h" |
+#include "chrome/browser/browser_process.h" |
#include "chrome/browser/extensions/api/image_writer_private/error_messages.h" |
#include "chrome/browser/extensions/api/image_writer_private/operation_manager.h" |
#include "chrome/browser/extensions/api/image_writer_private/write_from_url_operation.h" |
+#include "chrome/browser/profiles/profile.h" |
#include "content/public/browser/browser_thread.h" |
-#include "net/url_request/url_fetcher.h" |
+#include "content/public/browser/download_manager.h" |
+#include "content/public/browser/render_process_host.h" |
+#include "content/public/browser/render_view_host.h" |
+#include "extensions/common/error_utils.h" |
namespace extensions { |
namespace image_writer { |
@@ -17,126 +23,176 @@ |
WriteFromUrlOperation::WriteFromUrlOperation( |
base::WeakPtr<OperationManager> manager, |
const ExtensionId& extension_id, |
- net::URLRequestContextGetter* request_context, |
+ content::RenderViewHost* rvh, |
GURL url, |
const std::string& hash, |
- const std::string& device_path) |
- : Operation(manager, extension_id, device_path), |
- request_context_(request_context), |
+ bool saveImageAsDownload, |
+ const std::string& storage_unit_id) |
+ : Operation(manager, extension_id, storage_unit_id), |
+ rvh_(rvh), |
url_(url), |
hash_(hash), |
- download_continuation_() {} |
+ saveImageAsDownload_(saveImageAsDownload), |
+ download_stopped_(false), |
+ download_(NULL) { |
+} |
WriteFromUrlOperation::~WriteFromUrlOperation() { |
} |
-void WriteFromUrlOperation::StartImpl() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
- |
- GetDownloadTarget(base::Bind( |
- &WriteFromUrlOperation::Download, |
- this, |
- base::Bind( |
- &WriteFromUrlOperation::VerifyDownload, |
- this, |
- base::Bind( |
- &WriteFromUrlOperation::Unzip, |
- this, |
- base::Bind(&WriteFromUrlOperation::Write, |
- this, |
- base::Bind(&WriteFromUrlOperation::VerifyWrite, |
- this, |
- base::Bind(&WriteFromUrlOperation::Finish, |
- this))))))); |
-} |
- |
-void WriteFromUrlOperation::GetDownloadTarget( |
- const base::Closure& continuation) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
+void WriteFromUrlOperation::Start() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
+ |
+ SetStage(image_writer_api::STAGE_DOWNLOAD); |
+ |
+ if (saveImageAsDownload_){ |
+ BrowserThread::PostTask( |
+ BrowserThread::UI, |
+ FROM_HERE, |
+ base::Bind(&WriteFromUrlOperation::DownloadStart, this)); |
+ } else { |
+ BrowserThread::PostTask( |
+ BrowserThread::FILE, |
+ FROM_HERE, |
+ base::Bind(&WriteFromUrlOperation::CreateTempFile, this)); |
+ } |
+ |
+ AddCleanUpFunction(base::Bind(&WriteFromUrlOperation::DownloadCleanUp, this)); |
+} |
+ |
+void WriteFromUrlOperation::CreateTempFile() { |
if (IsCancelled()) { |
return; |
} |
- if (url_.ExtractFileName() == "") { |
- if (!base::CreateTemporaryFileInDir(temp_dir_.path(), &image_path_)) { |
- Error(error::kTempFileError); |
- return; |
- } |
+ tmp_file_.reset(new base::FilePath()); |
+ |
+ if (base::CreateTemporaryFile(tmp_file_.get())) { |
+ BrowserThread::PostTask( |
+ BrowserThread::UI, |
+ FROM_HERE, |
+ base::Bind(&WriteFromUrlOperation::DownloadStart, this)); |
} else { |
- base::FilePath file_name = |
- base::FilePath::FromUTF8Unsafe(url_.ExtractFileName()); |
- image_path_ = temp_dir_.path().Append(file_name); |
- } |
- |
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, continuation); |
-} |
- |
-void WriteFromUrlOperation::Download(const base::Closure& continuation) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
- |
- if (IsCancelled()) { |
- return; |
- } |
- |
- download_continuation_ = continuation; |
- |
- SetStage(image_writer_api::STAGE_DOWNLOAD); |
- |
- // Store the URL fetcher on this object so that it is destroyed before this |
- // object is. |
- url_fetcher_.reset(net::URLFetcher::Create(url_, net::URLFetcher::GET, this)); |
- |
- url_fetcher_->SetRequestContext(request_context_); |
- url_fetcher_->SaveResponseToFileAtPath( |
- image_path_, |
- BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)); |
- |
- AddCleanUpFunction( |
- base::Bind(&WriteFromUrlOperation::DestroyUrlFetcher, this)); |
- |
- url_fetcher_->Start(); |
-} |
- |
-void WriteFromUrlOperation::DestroyUrlFetcher() { url_fetcher_.reset(); } |
- |
-void WriteFromUrlOperation::OnURLFetchUploadProgress( |
- const net::URLFetcher* source, |
- int64 current, |
- int64 total) { |
- // No-op |
-} |
- |
-void WriteFromUrlOperation::OnURLFetchDownloadProgress( |
- const net::URLFetcher* source, |
- int64 current, |
- int64 total) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
- |
- if (IsCancelled()) { |
- url_fetcher_.reset(NULL); |
- } |
- |
- int progress = (kProgressComplete * current) / total; |
- |
- SetProgress(progress); |
-} |
- |
-void WriteFromUrlOperation::OnURLFetchComplete(const net::URLFetcher* source) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
- |
- if (source->GetStatus().is_success() && source->GetResponseCode() == 200) { |
- SetProgress(kProgressComplete); |
- |
- download_continuation_.Run(); |
- |
- // Remove the reference to ourselves in this closure. |
- download_continuation_ = base::Closure(); |
+ Error(error::kTempFileError); |
+ } |
+} |
+ |
+// The downloader runs on the UI thread. |
+void WriteFromUrlOperation::DownloadStart() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ |
+ if (download_stopped_) { |
+ return; |
+ } |
+ |
+ DVLOG(1) << "Starting download of URL: " << url_; |
+ |
+ Profile* current_profile = manager_->profile(); |
+ |
+ scoped_ptr<content::DownloadUrlParameters> download_params( |
+ new content::DownloadUrlParameters( |
+ url_, |
+ rvh_->GetProcess()->GetID(), |
+ rvh_->GetRoutingID(), |
+ current_profile->GetResourceContext())); |
+ |
+ if (tmp_file_.get()) { |
+ download_params->set_file_path(*tmp_file_); |
+ } |
+ |
+ download_params->set_callback( |
+ base::Bind(&WriteFromUrlOperation::OnDownloadStarted, this)); |
+ |
+ content::DownloadManager* download_manager = |
+ content::BrowserContext::GetDownloadManager(current_profile); |
+ download_manager->DownloadUrl(download_params.Pass()); |
+} |
+ |
+void WriteFromUrlOperation::OnDownloadStarted( |
+ content::DownloadItem* item, |
+ content::DownloadInterruptReason interrupt_reason) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ |
+ if (download_stopped_) { |
+ // At this point DownloadCleanUp was called but the |download_| wasn't |
+ // stored yet and still hasn't been cancelled. |
+ item->Cancel(true); |
+ return; |
+ } |
+ |
+ if (item) { |
+ DCHECK_EQ(content::DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason); |
+ |
+ download_ = item; |
+ download_->AddObserver(this); |
+ |
+ // Run at least once. |
+ OnDownloadUpdated(download_); |
} else { |
+ DCHECK_NE(content::DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason); |
+ std::string error_message = ErrorUtils::FormatErrorMessage( |
+ "Download failed: *", |
+ content::DownloadInterruptReasonToString(interrupt_reason)); |
+ Error(error_message); |
+ } |
+} |
+ |
+// Always called from the UI thread. |
+void WriteFromUrlOperation::OnDownloadUpdated(content::DownloadItem* download) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ |
+ if (download_stopped_) { |
+ return; |
+ } |
+ |
+ SetProgress(download->PercentComplete()); |
+ |
+ if (download->GetState() == content::DownloadItem::COMPLETE) { |
+ download_path_ = download_->GetTargetFilePath(); |
+ |
+ download_->RemoveObserver(this); |
+ download_ = NULL; |
+ |
+ BrowserThread::PostTask( |
+ BrowserThread::FILE, |
+ FROM_HERE, |
+ base::Bind(&WriteFromUrlOperation::DownloadComplete, this)); |
+ |
+ } else if (download->GetState() == content::DownloadItem::INTERRUPTED) { |
Error(error::kDownloadInterrupted); |
- } |
-} |
- |
-void WriteFromUrlOperation::VerifyDownload(const base::Closure& continuation) { |
+ } else if (download->GetState() == content::DownloadItem::CANCELLED) { |
+ Error(error::kDownloadCancelled); |
+ } |
+} |
+ |
+void WriteFromUrlOperation::DownloadComplete() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
+ DVLOG(1) << "Download complete."; |
+ |
+ SetProgress(kProgressComplete); |
+ |
+ VerifyDownloadStart(); |
+} |
+ |
+void WriteFromUrlOperation::DownloadCleanUp() { |
+ if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
+ BrowserThread::PostTask( |
+ BrowserThread::UI, |
+ FROM_HERE, |
+ base::Bind(&WriteFromUrlOperation::DownloadCleanUp, this)); |
+ return; |
+ } |
+ |
+ download_stopped_ = true; |
+ |
+ if (download_) { |
+ download_->RemoveObserver(this); |
+ download_->Cancel(true); |
+ download_ = NULL; |
+ } |
+} |
+ |
+void WriteFromUrlOperation::VerifyDownloadStart() { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
if (IsCancelled()) { |
@@ -145,26 +201,37 @@ |
// Skip verify if no hash. |
if (hash_.empty()) { |
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, continuation); |
- return; |
- } |
+ scoped_ptr<base::FilePath> download_path( |
+ new base::FilePath(download_path_)); |
+ UnzipStart(download_path.Pass()); |
+ return; |
+ } |
+ |
+ DVLOG(1) << "Download verification started."; |
SetStage(image_writer_api::STAGE_VERIFYDOWNLOAD); |
+ BrowserThread::PostTask( |
+ BrowserThread::FILE, |
+ FROM_HERE, |
+ base::Bind(&WriteFromUrlOperation::VerifyDownloadRun, this)); |
+} |
+ |
+void WriteFromUrlOperation::VerifyDownloadRun() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
+ scoped_ptr<base::FilePath> download_path(new base::FilePath(download_path_)); |
GetMD5SumOfFile( |
- image_path_, |
+ download_path.Pass(), |
0, |
0, |
kProgressComplete, |
- base::Bind( |
- &WriteFromUrlOperation::VerifyDownloadCompare, this, continuation)); |
+ base::Bind(&WriteFromUrlOperation::VerifyDownloadCompare, this)); |
} |
void WriteFromUrlOperation::VerifyDownloadCompare( |
- const base::Closure& continuation, |
- const std::string& download_hash) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
- if (download_hash != hash_) { |
+ scoped_ptr<std::string> download_hash) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
+ if (*download_hash != hash_) { |
Error(error::kDownloadHashError); |
return; |
} |
@@ -172,19 +239,21 @@ |
BrowserThread::PostTask( |
BrowserThread::FILE, |
FROM_HERE, |
- base::Bind( |
- &WriteFromUrlOperation::VerifyDownloadComplete, this, continuation)); |
-} |
- |
-void WriteFromUrlOperation::VerifyDownloadComplete( |
- const base::Closure& continuation) { |
+ base::Bind(&WriteFromUrlOperation::VerifyDownloadComplete, this)); |
+} |
+ |
+void WriteFromUrlOperation::VerifyDownloadComplete() { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
if (IsCancelled()) { |
return; |
} |
+ DVLOG(1) << "Download verification complete."; |
+ |
SetProgress(kProgressComplete); |
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, continuation); |
+ |
+ scoped_ptr<base::FilePath> download_path(new base::FilePath(download_path_)); |
+ UnzipStart(download_path.Pass()); |
} |
} // namespace image_writer |