- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / image_writer_private / write_from_url_operation.cc
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.
4
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"
17
18 namespace extensions {
19 namespace image_writer {
20
21 using content::BrowserThread;
22
23 WriteFromUrlOperation::WriteFromUrlOperation(
24     base::WeakPtr<OperationManager> manager,
25     const ExtensionId& extension_id,
26     content::RenderViewHost* rvh,
27     GURL url,
28     const std::string& hash,
29     bool saveImageAsDownload,
30     const std::string& storage_unit_id)
31     : Operation(manager, extension_id, storage_unit_id),
32       rvh_(rvh),
33       url_(url),
34       hash_(hash),
35       saveImageAsDownload_(saveImageAsDownload),
36       download_stopped_(false),
37       download_(NULL) {
38 }
39
40 WriteFromUrlOperation::~WriteFromUrlOperation() {
41 }
42
43 void WriteFromUrlOperation::Start() {
44   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
45
46   SetStage(image_writer_api::STAGE_DOWNLOAD);
47
48   if (saveImageAsDownload_){
49     BrowserThread::PostTask(
50         BrowserThread::UI,
51         FROM_HERE,
52         base::Bind(&WriteFromUrlOperation::DownloadStart, this));
53   } else {
54     BrowserThread::PostTask(
55         BrowserThread::FILE,
56         FROM_HERE,
57         base::Bind(&WriteFromUrlOperation::CreateTempFile, this));
58   }
59
60   AddCleanUpFunction(base::Bind(&WriteFromUrlOperation::DownloadCleanUp, this));
61 }
62
63 void WriteFromUrlOperation::CreateTempFile() {
64   if (IsCancelled()) {
65     return;
66   }
67
68   tmp_file_.reset(new base::FilePath());
69
70   if (file_util::CreateTemporaryFile(tmp_file_.get())) {
71     BrowserThread::PostTask(
72         BrowserThread::UI,
73         FROM_HERE,
74         base::Bind(&WriteFromUrlOperation::DownloadStart, this));
75   } else {
76     Error(error::kTempFile);
77   }
78 }
79
80 // The downloader runs on the UI thread.
81 void WriteFromUrlOperation::DownloadStart() {
82   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
83
84   if (download_stopped_) {
85     return;
86   }
87
88   DVLOG(1) << "Starting download of URL: " << url_;
89
90   Profile* current_profile = manager_->profile();
91
92   scoped_ptr<content::DownloadUrlParameters> download_params(
93       new content::DownloadUrlParameters(
94         url_,
95         rvh_->GetProcess()->GetID(),
96         rvh_->GetRoutingID(),
97         current_profile->GetResourceContext()));
98
99   if (tmp_file_.get()) {
100     download_params->set_file_path(*tmp_file_);
101   }
102
103   download_params->set_callback(
104       base::Bind(&WriteFromUrlOperation::OnDownloadStarted, this));
105
106   content::DownloadManager* download_manager =
107     content::BrowserContext::GetDownloadManager(current_profile);
108   download_manager->DownloadUrl(download_params.Pass());
109 }
110
111 void WriteFromUrlOperation::OnDownloadStarted(content::DownloadItem* item,
112                                               net::Error error) {
113   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
114
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.
118     item->Cancel(true);
119     return;
120   }
121
122   if (item) {
123     DCHECK_EQ(net::OK, error);
124
125     download_ = item;
126     download_->AddObserver(this);
127
128     // Run at least once.
129     OnDownloadUpdated(download_);
130   } else {
131     DCHECK_NE(net::OK, error);
132     std::string error_message = ErrorUtils::FormatErrorMessage(
133         "Download failed: *",
134         net::ErrorToString(error));
135     Error(error_message);
136   }
137 }
138
139 // Always called from the UI thread.
140 void WriteFromUrlOperation::OnDownloadUpdated(content::DownloadItem* download) {
141   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
142
143   if (download_stopped_) {
144     return;
145   }
146
147   SetProgress(download->PercentComplete());
148
149   if (download->GetState() == content::DownloadItem::COMPLETE) {
150     download_path_ = download_->GetTargetFilePath();
151
152     download_->RemoveObserver(this);
153     download_ = NULL;
154
155     BrowserThread::PostTask(
156         BrowserThread::FILE,
157         FROM_HERE,
158         base::Bind(&WriteFromUrlOperation::DownloadComplete, this));
159
160   } else if (download->GetState() == content::DownloadItem::INTERRUPTED) {
161     Error(error::kDownloadInterrupted);
162   } else if (download->GetState() == content::DownloadItem::CANCELLED) {
163     Error(error::kDownloadCancelled);
164   }
165 }
166
167 void WriteFromUrlOperation::DownloadComplete() {
168   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
169   DVLOG(1) << "Download complete.";
170
171   SetProgress(kProgressComplete);
172
173   VerifyDownloadStart();
174 }
175
176 void WriteFromUrlOperation::DownloadCleanUp() {
177   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
178     BrowserThread::PostTask(
179         BrowserThread::UI,
180         FROM_HERE,
181         base::Bind(&WriteFromUrlOperation::DownloadCleanUp, this));
182     return;
183   }
184
185   download_stopped_ = true;
186
187   if (download_) {
188     download_->RemoveObserver(this);
189     download_->Cancel(true);
190     download_ = NULL;
191   }
192 }
193
194 void WriteFromUrlOperation::VerifyDownloadStart() {
195   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
196
197   if (IsCancelled()) {
198     return;
199   }
200
201   // Skip verify if no hash.
202   if (hash_.empty()) {
203     scoped_ptr<base::FilePath> download_path(
204         new base::FilePath(download_path_));
205     UnzipStart(download_path.Pass());
206     return;
207   }
208
209   DVLOG(1) << "Download verification started.";
210
211   SetStage(image_writer_api::STAGE_VERIFYDOWNLOAD);
212
213   BrowserThread::PostTask(
214       BrowserThread::FILE,
215       FROM_HERE,
216       base::Bind(&WriteFromUrlOperation::VerifyDownloadRun, this));
217 }
218
219 void WriteFromUrlOperation::VerifyDownloadRun() {
220   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
221   scoped_ptr<base::FilePath> download_path(new base::FilePath(download_path_));
222   GetMD5SumOfFile(
223       download_path.Pass(),
224       0,
225       0,
226       kProgressComplete,
227       base::Bind(&WriteFromUrlOperation::VerifyDownloadCompare, this));
228 }
229
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);
235     return;
236   }
237
238   BrowserThread::PostTask(
239       BrowserThread::FILE,
240       FROM_HERE,
241       base::Bind(&WriteFromUrlOperation::VerifyDownloadComplete, this));
242 }
243
244 void WriteFromUrlOperation::VerifyDownloadComplete() {
245   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
246   if (IsCancelled()) {
247     return;
248   }
249
250   DVLOG(1) << "Download verification complete.";
251
252   SetProgress(kProgressComplete);
253
254   scoped_ptr<base::FilePath> download_path(new base::FilePath(download_path_));
255   UnzipStart(download_path.Pass());
256 }
257
258 } // namespace image_writer
259 } // namespace extensions