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
3 // found in the LICENSE file.
5 #include "base/file_util.h"
6 #include "base/threading/worker_pool.h"
7 #include "chrome/browser/browser_process.h"
8 #include "chrome/browser/extensions/api/image_writer_private/error_messages.h"
9 #include "chrome/browser/extensions/api/image_writer_private/operation_manager.h"
10 #include "chrome/browser/extensions/api/image_writer_private/write_from_url_operation.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "content/public/browser/download_manager.h"
14 #include "content/public/browser/render_process_host.h"
15 #include "content/public/browser/render_view_host.h"
16 #include "extensions/common/error_utils.h"
18 namespace extensions {
19 namespace image_writer {
21 using content::BrowserThread;
23 WriteFromUrlOperation::WriteFromUrlOperation(
24 base::WeakPtr<OperationManager> manager,
25 const ExtensionId& extension_id,
26 content::RenderViewHost* rvh,
28 const std::string& hash,
29 bool saveImageAsDownload,
30 const std::string& storage_unit_id)
31 : Operation(manager, extension_id, storage_unit_id),
35 saveImageAsDownload_(saveImageAsDownload),
36 download_stopped_(false),
40 WriteFromUrlOperation::~WriteFromUrlOperation() {
43 void WriteFromUrlOperation::Start() {
44 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
46 SetStage(image_writer_api::STAGE_DOWNLOAD);
48 if (saveImageAsDownload_){
49 BrowserThread::PostTask(
52 base::Bind(&WriteFromUrlOperation::DownloadStart, this));
54 BrowserThread::PostTask(
57 base::Bind(&WriteFromUrlOperation::CreateTempFile, this));
60 AddCleanUpFunction(base::Bind(&WriteFromUrlOperation::DownloadCleanUp, this));
63 void WriteFromUrlOperation::CreateTempFile() {
68 tmp_file_.reset(new base::FilePath());
70 if (file_util::CreateTemporaryFile(tmp_file_.get())) {
71 BrowserThread::PostTask(
74 base::Bind(&WriteFromUrlOperation::DownloadStart, this));
76 Error(error::kTempFile);
80 // The downloader runs on the UI thread.
81 void WriteFromUrlOperation::DownloadStart() {
82 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
84 if (download_stopped_) {
88 DVLOG(1) << "Starting download of URL: " << url_;
90 Profile* current_profile = manager_->profile();
92 scoped_ptr<content::DownloadUrlParameters> download_params(
93 new content::DownloadUrlParameters(
95 rvh_->GetProcess()->GetID(),
97 current_profile->GetResourceContext()));
99 if (tmp_file_.get()) {
100 download_params->set_file_path(*tmp_file_);
103 download_params->set_callback(
104 base::Bind(&WriteFromUrlOperation::OnDownloadStarted, this));
106 content::DownloadManager* download_manager =
107 content::BrowserContext::GetDownloadManager(current_profile);
108 download_manager->DownloadUrl(download_params.Pass());
111 void WriteFromUrlOperation::OnDownloadStarted(content::DownloadItem* item,
113 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
115 if (download_stopped_) {
116 // At this point DownloadCleanUp was called but the |download_| wasn't
117 // stored yet and still hasn't been cancelled.
123 DCHECK_EQ(net::OK, error);
126 download_->AddObserver(this);
128 // Run at least once.
129 OnDownloadUpdated(download_);
131 DCHECK_NE(net::OK, error);
132 std::string error_message = ErrorUtils::FormatErrorMessage(
133 "Download failed: *",
134 net::ErrorToString(error));
135 Error(error_message);
139 // Always called from the UI thread.
140 void WriteFromUrlOperation::OnDownloadUpdated(content::DownloadItem* download) {
141 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
143 if (download_stopped_) {
147 SetProgress(download->PercentComplete());
149 if (download->GetState() == content::DownloadItem::COMPLETE) {
150 download_path_ = download_->GetTargetFilePath();
152 download_->RemoveObserver(this);
155 BrowserThread::PostTask(
158 base::Bind(&WriteFromUrlOperation::DownloadComplete, this));
160 } else if (download->GetState() == content::DownloadItem::INTERRUPTED) {
161 Error(error::kDownloadInterrupted);
162 } else if (download->GetState() == content::DownloadItem::CANCELLED) {
163 Error(error::kDownloadCancelled);
167 void WriteFromUrlOperation::DownloadComplete() {
168 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
169 DVLOG(1) << "Download complete.";
171 SetProgress(kProgressComplete);
173 VerifyDownloadStart();
176 void WriteFromUrlOperation::DownloadCleanUp() {
177 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
178 BrowserThread::PostTask(
181 base::Bind(&WriteFromUrlOperation::DownloadCleanUp, this));
185 download_stopped_ = true;
188 download_->RemoveObserver(this);
189 download_->Cancel(true);
194 void WriteFromUrlOperation::VerifyDownloadStart() {
195 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
201 // Skip verify if no hash.
203 scoped_ptr<base::FilePath> download_path(
204 new base::FilePath(download_path_));
205 UnzipStart(download_path.Pass());
209 DVLOG(1) << "Download verification started.";
211 SetStage(image_writer_api::STAGE_VERIFYDOWNLOAD);
213 BrowserThread::PostTask(
216 base::Bind(&WriteFromUrlOperation::VerifyDownloadRun, this));
219 void WriteFromUrlOperation::VerifyDownloadRun() {
220 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
221 scoped_ptr<base::FilePath> download_path(new base::FilePath(download_path_));
223 download_path.Pass(),
227 base::Bind(&WriteFromUrlOperation::VerifyDownloadCompare, this));
230 void WriteFromUrlOperation::VerifyDownloadCompare(
231 scoped_ptr<std::string> download_hash) {
232 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
233 if (*download_hash != hash_) {
234 Error(error::kDownloadHash);
238 BrowserThread::PostTask(
241 base::Bind(&WriteFromUrlOperation::VerifyDownloadComplete, this));
244 void WriteFromUrlOperation::VerifyDownloadComplete() {
245 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
250 DVLOG(1) << "Download verification complete.";
252 SetProgress(kProgressComplete);
254 scoped_ptr<base::FilePath> download_path(new base::FilePath(download_path_));
255 UnzipStart(download_path.Pass());
258 } // namespace image_writer
259 } // namespace extensions