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

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 compilation errors. 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 bool saveImageAsDownload,
30 const std::string& storage_unit_id) 24 const std::string& device_path)
31 : Operation(manager, extension_id, storage_unit_id), 25 : Operation(manager, extension_id, device_path),
32 rvh_(rvh), 26 request_context_(request_context),
33 url_(url), 27 url_(url),
34 hash_(hash), 28 hash_(hash),
35 saveImageAsDownload_(saveImageAsDownload), 29 saveImageAsDownload_(saveImageAsDownload),
36 download_stopped_(false), 30 download_continuation_() {
37 download_(NULL) {
38 } 31 }
39 32
40 WriteFromUrlOperation::~WriteFromUrlOperation() { 33 WriteFromUrlOperation::~WriteFromUrlOperation() {
41 } 34 }
42 35
43 void WriteFromUrlOperation::Start() { 36 void WriteFromUrlOperation::Start() {
44 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 37 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
45 38
46 SetStage(image_writer_api::STAGE_DOWNLOAD); 39 GetDownloadTarget(
tbarzic 2014/02/07 22:06:42 I like this cascading :)
Drew Haven 2014/02/11 00:50:15 I like that it makes the stages of an operation ve
47 40 base::Bind(
48 if (saveImageAsDownload_){ 41 &WriteFromUrlOperation::Download,
49 BrowserThread::PostTask( 42 this,
50 BrowserThread::UI, 43 base::Bind(
51 FROM_HERE, 44 &WriteFromUrlOperation::VerifyDownload,
52 base::Bind(&WriteFromUrlOperation::DownloadStart, this)); 45 this,
53 } else { 46 base::Bind(
54 BrowserThread::PostTask( 47 &WriteFromUrlOperation::Unzip,
55 BrowserThread::FILE, 48 this,
56 FROM_HERE, 49 base::Bind(
57 base::Bind(&WriteFromUrlOperation::CreateTempFile, this)); 50 &WriteFromUrlOperation::Write,
58 } 51 this,
59 52 base::Bind(
60 AddCleanUpFunction(base::Bind(&WriteFromUrlOperation::DownloadCleanUp, this)); 53 &WriteFromUrlOperation::VerifyWrite,
54 this,
55 base::Bind(
56 &WriteFromUrlOperation::Finish, this)))))));
61 } 57 }
62 58
63 void WriteFromUrlOperation::CreateTempFile() { 59 void WriteFromUrlOperation::GetDownloadTarget(
60 const base::Closure& continuation) {
61 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
64 if (IsCancelled()) { 62 if (IsCancelled()) {
65 return; 63 return;
66 } 64 }
67 65
68 tmp_file_.reset(new base::FilePath()); 66 if (saveImageAsDownload_) {
69 67 Error("Not supported yet.");
70 if (base::CreateTemporaryFile(tmp_file_.get())) { 68 return;
71 BrowserThread::PostTask(
72 BrowserThread::UI,
73 FROM_HERE,
74 base::Bind(&WriteFromUrlOperation::DownloadStart, this));
75 } else { 69 } else {
76 Error(error::kTempFileError); 70 if (url_.ExtractFileName() == "") {
71 if (base::CreateTemporaryFileInDir(temp_dir_.path(), &image_path_)) {
72 continuation.Run();
73 } else {
74 Error(error::kTempFileError);
75 }
76 } else {
77 #if defined(OS_WIN)
78 base::FilePath file_name =
79 base::FilePath::FromUTF16Unsafe(url_.ExtractFileName());
80 #else
81 base::FilePath file_name = base::FilePath(url_.ExtractFileName());
82 #endif
83 image_path_ = temp_dir_.path().Append(file_name);
84 continuation.Run();
85 }
77 } 86 }
78 } 87 }
79 88
80 // The downloader runs on the UI thread. 89 // The downloader runs on the UI thread.
81 void WriteFromUrlOperation::DownloadStart() { 90 void WriteFromUrlOperation::Download(const base::Closure& continuation) {
82 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 91 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
83 92
84 if (download_stopped_) { 93 if (IsCancelled()) {
85 return; 94 return;
86 } 95 }
87 96
88 DVLOG(1) << "Starting download of URL: " << url_; 97 download_continuation_ = continuation;
89 98
90 Profile* current_profile = manager_->profile(); 99 SetStage(image_writer_api::STAGE_DOWNLOAD);
91 100
92 scoped_ptr<content::DownloadUrlParameters> download_params( 101 // Store the URL fetcher on this object so that it is destroyed before this
93 new content::DownloadUrlParameters( 102 // object is.
94 url_, 103 url_fetcher_.reset(net::URLFetcher::Create(url_, net::URLFetcher::GET, this));
95 rvh_->GetProcess()->GetID(),
96 rvh_->GetRoutingID(),
97 current_profile->GetResourceContext()));
98 104
99 if (tmp_file_.get()) { 105 url_fetcher_->SetRequestContext(request_context_);
100 download_params->set_file_path(*tmp_file_); 106 url_fetcher_->SaveResponseToFileAtPath(
101 } 107 image_path_,
108 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
102 109
103 download_params->set_callback( 110 url_fetcher_->Start();
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 } 111 }
110 112
111 void WriteFromUrlOperation::OnDownloadStarted( 113 void WriteFromUrlOperation::OnURLFetchUploadProgress(
112 content::DownloadItem* item, 114 const net::URLFetcher* source,
113 content::DownloadInterruptReason interrupt_reason) { 115 int64 current,
114 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 116 int64 total) {
117 // No-op
118 }
115 119
116 if (download_stopped_) { 120 void WriteFromUrlOperation::OnURLFetchDownloadProgress(
117 // At this point DownloadCleanUp was called but the |download_| wasn't 121 const net::URLFetcher* source,
118 // stored yet and still hasn't been cancelled. 122 int64 current,
119 item->Cancel(true); 123 int64 total) {
120 return; 124 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
125
126 if (IsCancelled()) {
127 url_fetcher_.reset(NULL);
121 } 128 }
129 SetProgress(kProgressComplete * current / total);
130 }
122 131
123 if (item) { 132 void WriteFromUrlOperation::OnURLFetchComplete(const net::URLFetcher* source) {
124 DCHECK_EQ(content::DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason); 133 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
125 134
126 download_ = item; 135 if (source->GetStatus().is_success() && source->GetResponseCode() == 200) {
127 download_->AddObserver(this); 136 SetProgress(kProgressComplete);
128 137
129 // Run at least once. 138 download_continuation_.Run();
130 OnDownloadUpdated(download_);
131 } else { 139 } else {
132 DCHECK_NE(content::DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason); 140 Error(error::kDownloadInterrupted);
133 std::string error_message = ErrorUtils::FormatErrorMessage(
134 "Download failed: *",
135 content::DownloadInterruptReasonToString(interrupt_reason));
136 Error(error_message);
137 } 141 }
138 } 142 }
139 143
140 // Always called from the UI thread. 144 void WriteFromUrlOperation::VerifyDownload(
141 void WriteFromUrlOperation::OnDownloadUpdated(content::DownloadItem* download) { 145 const base::Closure& continuation) {
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)); 146 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
197 147
198 if (IsCancelled()) { 148 if (IsCancelled()) {
199 return; 149 return;
200 } 150 }
201 151
202 // Skip verify if no hash. 152 // Skip verify if no hash.
203 if (hash_.empty()) { 153 if (hash_.empty()) {
204 scoped_ptr<base::FilePath> download_path( 154 continuation.Run();
205 new base::FilePath(download_path_));
206 UnzipStart(download_path.Pass());
207 return; 155 return;
208 } 156 }
209 157
210 DVLOG(1) << "Download verification started.";
211
212 SetStage(image_writer_api::STAGE_VERIFYDOWNLOAD); 158 SetStage(image_writer_api::STAGE_VERIFYDOWNLOAD);
213 159
214 BrowserThread::PostTask( 160 BrowserThread::PostTask(
215 BrowserThread::FILE, 161 BrowserThread::FILE,
216 FROM_HERE, 162 FROM_HERE,
217 base::Bind(&WriteFromUrlOperation::VerifyDownloadRun, this)); 163 base::Bind(&WriteFromUrlOperation::VerifyDownloadRun,
164 this,
165 continuation));
218 } 166 }
219 167
220 void WriteFromUrlOperation::VerifyDownloadRun() { 168 void WriteFromUrlOperation::VerifyDownloadRun(
169 const base::Closure& continuation) {
221 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 170 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
222 scoped_ptr<base::FilePath> download_path(new base::FilePath(download_path_));
223 GetMD5SumOfFile( 171 GetMD5SumOfFile(
224 download_path.Pass(), 172 image_path_,
225 0, 173 0,
226 0, 174 100,
227 kProgressComplete, 175 kProgressComplete,
228 base::Bind(&WriteFromUrlOperation::VerifyDownloadCompare, this)); 176 base::Bind(&WriteFromUrlOperation::VerifyDownloadCompare,
177 this,
178 continuation));
229 } 179 }
230 180
231 void WriteFromUrlOperation::VerifyDownloadCompare( 181 void WriteFromUrlOperation::VerifyDownloadCompare(
232 scoped_ptr<std::string> download_hash) { 182 const base::Closure& continuation,
183 const std::string& download_hash) {
233 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 184 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
234 if (*download_hash != hash_) { 185 if (download_hash != hash_) {
235 Error(error::kDownloadHashError); 186 Error(error::kDownloadHashError);
236 return; 187 return;
237 } 188 }
238 189
239 BrowserThread::PostTask( 190 BrowserThread::PostTask(
240 BrowserThread::FILE, 191 BrowserThread::FILE,
241 FROM_HERE, 192 FROM_HERE,
242 base::Bind(&WriteFromUrlOperation::VerifyDownloadComplete, this)); 193 base::Bind(&WriteFromUrlOperation::VerifyDownloadComplete,
194 this,
195 continuation));
243 } 196 }
244 197
245 void WriteFromUrlOperation::VerifyDownloadComplete() { 198 void WriteFromUrlOperation::VerifyDownloadComplete(
199 const base::Closure& continuation) {
246 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 200 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
247 if (IsCancelled()) { 201 if (IsCancelled()) {
248 return; 202 return;
249 } 203 }
250 204
251 DVLOG(1) << "Download verification complete.";
252
253 SetProgress(kProgressComplete); 205 SetProgress(kProgressComplete);
254 206
255 scoped_ptr<base::FilePath> download_path(new base::FilePath(download_path_)); 207 continuation.Run();
256 UnzipStart(download_path.Pass());
257 } 208 }
258 209
259 } // namespace image_writer 210 } // namespace image_writer
260 } // namespace extensions 211 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698