Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(61)

Side by Side Diff: chrome/browser/extensions/api/image_writer_private/write_from_url_operation.cc

Issue 149313003: Significantly cleans up the ImageWriter Operation class and subclasses. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixes cross-compilation and test issues. Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 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 "base/file_util.h" 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" 6 #include "chrome/browser/extensions/api/image_writer_private/error_messages.h"
9 #include "chrome/browser/extensions/api/image_writer_private/operation_manager.h " 7 #include "chrome/browser/extensions/api/image_writer_private/operation_manager.h "
10 #include "chrome/browser/extensions/api/image_writer_private/write_from_url_oper ation.h" 8 #include "chrome/browser/extensions/api/image_writer_private/write_from_url_oper ation.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "content/public/browser/browser_thread.h" 9 #include "content/public/browser/browser_thread.h"
13 #include "content/public/browser/download_manager.h" 10 #include "net/url_request/url_fetcher.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 11
18 namespace extensions { 12 namespace extensions {
19 namespace image_writer { 13 namespace image_writer {
20 14
21 using content::BrowserThread; 15 using content::BrowserThread;
22 16
23 WriteFromUrlOperation::WriteFromUrlOperation( 17 WriteFromUrlOperation::WriteFromUrlOperation(
24 base::WeakPtr<OperationManager> manager, 18 base::WeakPtr<OperationManager> manager,
25 const ExtensionId& extension_id, 19 const ExtensionId& extension_id,
26 content::RenderViewHost* rvh, 20 net::URLRequestContextGetter* request_context,
27 GURL url, 21 GURL url,
28 const std::string& hash, 22 const std::string& hash,
29 bool saveImageAsDownload, 23 const std::string& device_path)
30 const std::string& storage_unit_id) 24 : Operation(manager, extension_id, device_path),
31 : Operation(manager, extension_id, storage_unit_id), 25 request_context_(request_context),
32 rvh_(rvh),
33 url_(url), 26 url_(url),
34 hash_(hash), 27 hash_(hash),
35 saveImageAsDownload_(saveImageAsDownload), 28 download_continuation_() {}
36 download_stopped_(false),
37 download_(NULL) {
38 }
39 29
40 WriteFromUrlOperation::~WriteFromUrlOperation() { 30 WriteFromUrlOperation::~WriteFromUrlOperation() {
41 } 31 }
42 32
43 void WriteFromUrlOperation::Start() { 33 void WriteFromUrlOperation::StartImpl() {
44 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 34 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
45 35
46 SetStage(image_writer_api::STAGE_DOWNLOAD); 36 GetDownloadTarget(base::Bind(
47 37 &WriteFromUrlOperation::Download,
48 if (saveImageAsDownload_){ 38 this,
49 BrowserThread::PostTask( 39 base::Bind(
50 BrowserThread::UI, 40 &WriteFromUrlOperation::VerifyDownload,
51 FROM_HERE, 41 this,
52 base::Bind(&WriteFromUrlOperation::DownloadStart, this)); 42 base::Bind(
53 } else { 43 &WriteFromUrlOperation::Unzip,
54 BrowserThread::PostTask( 44 this,
55 BrowserThread::FILE, 45 base::Bind(&WriteFromUrlOperation::Write,
56 FROM_HERE, 46 this,
57 base::Bind(&WriteFromUrlOperation::CreateTempFile, this)); 47 base::Bind(&WriteFromUrlOperation::VerifyWrite,
58 } 48 this,
59 49 base::Bind(&WriteFromUrlOperation::Finish,
60 AddCleanUpFunction(base::Bind(&WriteFromUrlOperation::DownloadCleanUp, this)); 50 this)))))));
61 } 51 }
62 52
63 void WriteFromUrlOperation::CreateTempFile() { 53 void WriteFromUrlOperation::GetDownloadTarget(
54 const base::Closure& continuation) {
55 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
64 if (IsCancelled()) { 56 if (IsCancelled()) {
65 return; 57 return;
66 } 58 }
67 59
68 tmp_file_.reset(new base::FilePath()); 60 if (url_.ExtractFileName() == "") {
61 if (!base::CreateTemporaryFileInDir(temp_dir_.path(), &image_path_)) {
62 Error(error::kTempFileError);
63 return;
64 }
65 } else {
66 base::FilePath file_name =
67 base::FilePath::FromUTF8Unsafe(url_.ExtractFileName());
68 image_path_ = temp_dir_.path().Append(file_name);
69 }
69 70
70 if (base::CreateTemporaryFile(tmp_file_.get())) { 71 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, continuation);
71 BrowserThread::PostTask( 72 }
72 BrowserThread::UI, 73
73 FROM_HERE, 74 void WriteFromUrlOperation::Download(const base::Closure& continuation) {
74 base::Bind(&WriteFromUrlOperation::DownloadStart, this)); 75 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
76
77 if (IsCancelled()) {
78 return;
79 }
80
81 download_continuation_ = continuation;
82
83 SetStage(image_writer_api::STAGE_DOWNLOAD);
84
85 // Store the URL fetcher on this object so that it is destroyed before this
86 // object is.
87 url_fetcher_.reset(net::URLFetcher::Create(url_, net::URLFetcher::GET, this));
88
89 url_fetcher_->SetRequestContext(request_context_);
90 url_fetcher_->SaveResponseToFileAtPath(
91 image_path_,
92 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
93
94 AddCleanUpFunction(
95 base::Bind(&WriteFromUrlOperation::DestroyUrlFetcher, this));
96
97 url_fetcher_->Start();
98 }
99
100 void WriteFromUrlOperation::DestroyUrlFetcher() { url_fetcher_.reset(); }
101
102 void WriteFromUrlOperation::OnURLFetchUploadProgress(
103 const net::URLFetcher* source,
104 int64 current,
105 int64 total) {
106 // No-op
107 }
108
109 void WriteFromUrlOperation::OnURLFetchDownloadProgress(
110 const net::URLFetcher* source,
111 int64 current,
112 int64 total) {
113 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
114
115 if (IsCancelled()) {
116 url_fetcher_.reset(NULL);
117 }
118
119 int progress = (kProgressComplete * current) / total;
120
121 SetProgress(progress);
122 }
123
124 void WriteFromUrlOperation::OnURLFetchComplete(const net::URLFetcher* source) {
125 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
126
127 if (source->GetStatus().is_success() && source->GetResponseCode() == 200) {
128 SetProgress(kProgressComplete);
129
130 download_continuation_.Run();
131
132 // Remove the reference to ourselves in this closure.
133 download_continuation_ = base::Closure();
75 } else { 134 } else {
76 Error(error::kTempFileError); 135 Error(error::kDownloadInterrupted);
77 } 136 }
78 } 137 }
79 138
80 // The downloader runs on the UI thread. 139 void WriteFromUrlOperation::VerifyDownload(const base::Closure& continuation) {
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(
112 content::DownloadItem* item,
113 content::DownloadInterruptReason interrupt_reason) {
114 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
115
116 if (download_stopped_) {
117 // At this point DownloadCleanUp was called but the |download_| wasn't
118 // stored yet and still hasn't been cancelled.
119 item->Cancel(true);
120 return;
121 }
122
123 if (item) {
124 DCHECK_EQ(content::DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason);
125
126 download_ = item;
127 download_->AddObserver(this);
128
129 // Run at least once.
130 OnDownloadUpdated(download_);
131 } else {
132 DCHECK_NE(content::DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason);
133 std::string error_message = ErrorUtils::FormatErrorMessage(
134 "Download failed: *",
135 content::DownloadInterruptReasonToString(interrupt_reason));
136 Error(error_message);
137 }
138 }
139
140 // Always called from the UI thread.
141 void WriteFromUrlOperation::OnDownloadUpdated(content::DownloadItem* download) {
142 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
143
144 if (download_stopped_) {
145 return;
146 }
147
148 SetProgress(download->PercentComplete());
149
150 if (download->GetState() == content::DownloadItem::COMPLETE) {
151 download_path_ = download_->GetTargetFilePath();
152
153 download_->RemoveObserver(this);
154 download_ = NULL;
155
156 BrowserThread::PostTask(
157 BrowserThread::FILE,
158 FROM_HERE,
159 base::Bind(&WriteFromUrlOperation::DownloadComplete, this));
160
161 } else if (download->GetState() == content::DownloadItem::INTERRUPTED) {
162 Error(error::kDownloadInterrupted);
163 } else if (download->GetState() == content::DownloadItem::CANCELLED) {
164 Error(error::kDownloadCancelled);
165 }
166 }
167
168 void WriteFromUrlOperation::DownloadComplete() {
169 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
170 DVLOG(1) << "Download complete.";
171
172 SetProgress(kProgressComplete);
173
174 VerifyDownloadStart();
175 }
176
177 void WriteFromUrlOperation::DownloadCleanUp() {
178 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
179 BrowserThread::PostTask(
180 BrowserThread::UI,
181 FROM_HERE,
182 base::Bind(&WriteFromUrlOperation::DownloadCleanUp, this));
183 return;
184 }
185
186 download_stopped_ = true;
187
188 if (download_) {
189 download_->RemoveObserver(this);
190 download_->Cancel(true);
191 download_ = NULL;
192 }
193 }
194
195 void WriteFromUrlOperation::VerifyDownloadStart() {
196 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
197 141
198 if (IsCancelled()) { 142 if (IsCancelled()) {
199 return; 143 return;
200 } 144 }
201 145
202 // Skip verify if no hash. 146 // Skip verify if no hash.
203 if (hash_.empty()) { 147 if (hash_.empty()) {
204 scoped_ptr<base::FilePath> download_path( 148 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, continuation);
205 new base::FilePath(download_path_));
206 UnzipStart(download_path.Pass());
207 return; 149 return;
208 } 150 }
209 151
210 DVLOG(1) << "Download verification started.";
211
212 SetStage(image_writer_api::STAGE_VERIFYDOWNLOAD); 152 SetStage(image_writer_api::STAGE_VERIFYDOWNLOAD);
213 153
214 BrowserThread::PostTask(
215 BrowserThread::FILE,
216 FROM_HERE,
217 base::Bind(&WriteFromUrlOperation::VerifyDownloadRun, this));
218 }
219
220 void WriteFromUrlOperation::VerifyDownloadRun() {
221 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
222 scoped_ptr<base::FilePath> download_path(new base::FilePath(download_path_));
223 GetMD5SumOfFile( 154 GetMD5SumOfFile(
224 download_path.Pass(), 155 image_path_,
225 0, 156 0,
226 0, 157 0,
227 kProgressComplete, 158 kProgressComplete,
228 base::Bind(&WriteFromUrlOperation::VerifyDownloadCompare, this)); 159 base::Bind(
160 &WriteFromUrlOperation::VerifyDownloadCompare, this, continuation));
229 } 161 }
230 162
231 void WriteFromUrlOperation::VerifyDownloadCompare( 163 void WriteFromUrlOperation::VerifyDownloadCompare(
232 scoped_ptr<std::string> download_hash) { 164 const base::Closure& continuation,
165 const std::string& download_hash) {
233 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 166 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
234 if (*download_hash != hash_) { 167 if (download_hash != hash_) {
235 Error(error::kDownloadHashError); 168 Error(error::kDownloadHashError);
236 return; 169 return;
237 } 170 }
238 171
239 BrowserThread::PostTask( 172 BrowserThread::PostTask(
240 BrowserThread::FILE, 173 BrowserThread::FILE,
241 FROM_HERE, 174 FROM_HERE,
242 base::Bind(&WriteFromUrlOperation::VerifyDownloadComplete, this)); 175 base::Bind(
176 &WriteFromUrlOperation::VerifyDownloadComplete, this, continuation));
243 } 177 }
244 178
245 void WriteFromUrlOperation::VerifyDownloadComplete() { 179 void WriteFromUrlOperation::VerifyDownloadComplete(
180 const base::Closure& continuation) {
246 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 181 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
247 if (IsCancelled()) { 182 if (IsCancelled()) {
248 return; 183 return;
249 } 184 }
250 185
251 DVLOG(1) << "Download verification complete.";
252
253 SetProgress(kProgressComplete); 186 SetProgress(kProgressComplete);
254 187 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, continuation);
255 scoped_ptr<base::FilePath> download_path(new base::FilePath(download_path_));
256 UnzipStart(download_path.Pass());
257 } 188 }
258 189
259 } // namespace image_writer 190 } // namespace image_writer
260 } // namespace extensions 191 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698