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

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: Review feedback: Creates StartImpl function, updates platformfile lifetime to use passed ScopedPlat… 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 }
39 31
40 WriteFromUrlOperation::~WriteFromUrlOperation() { 32 WriteFromUrlOperation::~WriteFromUrlOperation() {
41 } 33 }
42 34
43 void WriteFromUrlOperation::Start() { 35 void WriteFromUrlOperation::StartImpl() {
44 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 36 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
45 37
46 SetStage(image_writer_api::STAGE_DOWNLOAD); 38 GetDownloadTarget(base::Bind(
47 39 &WriteFromUrlOperation::Download,
48 if (saveImageAsDownload_){ 40 this,
49 BrowserThread::PostTask( 41 base::Bind(
50 BrowserThread::UI, 42 &WriteFromUrlOperation::VerifyDownload,
51 FROM_HERE, 43 this,
52 base::Bind(&WriteFromUrlOperation::DownloadStart, this)); 44 base::Bind(
53 } else { 45 &WriteFromUrlOperation::Unzip,
54 BrowserThread::PostTask( 46 this,
55 BrowserThread::FILE, 47 base::Bind(&WriteFromUrlOperation::Write,
56 FROM_HERE, 48 this,
57 base::Bind(&WriteFromUrlOperation::CreateTempFile, this)); 49 base::Bind(&WriteFromUrlOperation::VerifyWrite,
58 } 50 this,
59 51 base::Bind(&WriteFromUrlOperation::Finish,
60 AddCleanUpFunction(base::Bind(&WriteFromUrlOperation::DownloadCleanUp, this)); 52 this)))))));
61 } 53 }
62 54
63 void WriteFromUrlOperation::CreateTempFile() { 55 void WriteFromUrlOperation::GetDownloadTarget(
56 const base::Closure& continuation) {
57 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
64 if (IsCancelled()) { 58 if (IsCancelled()) {
65 return; 59 return;
66 } 60 }
67 61
68 tmp_file_.reset(new base::FilePath()); 62 if (url_.ExtractFileName() == "") {
63 if (!base::CreateTemporaryFileInDir(temp_dir_.path(), &image_path_)) {
64 Error(error::kTempFileError);
65 return;
66 }
67 } else {
68 #if defined(OS_WIN)
69 base::FilePath file_name =
70 base::FilePath::FromUTF16Unsafe(url_.ExtractFileName());
71 #else
72 base::FilePath file_name = base::FilePath(url_.ExtractFileName());
73 #endif
74 image_path_ = temp_dir_.path().Append(file_name);
75 }
69 76
70 if (base::CreateTemporaryFile(tmp_file_.get())) { 77 continuation.Run();
71 BrowserThread::PostTask( 78 }
72 BrowserThread::UI, 79
73 FROM_HERE, 80 void WriteFromUrlOperation::Download(const base::Closure& continuation) {
74 base::Bind(&WriteFromUrlOperation::DownloadStart, this)); 81 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
82
83 if (IsCancelled()) {
84 return;
85 }
86
87 download_continuation_ = continuation;
88
89 SetStage(image_writer_api::STAGE_DOWNLOAD);
90
91 // Store the URL fetcher on this object so that it is destroyed before this
92 // object is.
93 url_fetcher_.reset(net::URLFetcher::Create(url_, net::URLFetcher::GET, this));
94
95 url_fetcher_->SetRequestContext(request_context_);
96 url_fetcher_->SaveResponseToFileAtPath(
97 image_path_,
98 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
99
100 AddCleanUpFunction(
101 base::Bind(&WriteFromUrlOperation::DestroyUrlFetcher, this));
102
103 url_fetcher_->Start();
104 }
105
106 void WriteFromUrlOperation::DestroyUrlFetcher() { url_fetcher_.reset(); }
107
108 void WriteFromUrlOperation::OnURLFetchUploadProgress(
109 const net::URLFetcher* source,
110 int64 current,
111 int64 total) {
112 // No-op
113 }
114
115 void WriteFromUrlOperation::OnURLFetchDownloadProgress(
116 const net::URLFetcher* source,
117 int64 current,
118 int64 total) {
119 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
120
121 if (IsCancelled()) {
122 url_fetcher_.reset(NULL);
123 }
124
125 int progress = (kProgressComplete * current) / total;
126
127 SetProgress(progress);
128 }
129
130 void WriteFromUrlOperation::OnURLFetchComplete(const net::URLFetcher* source) {
131 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
132
133 if (source->GetStatus().is_success() && source->GetResponseCode() == 200) {
134 SetProgress(kProgressComplete);
135
136 download_continuation_.Run();
137
138 // Remove the reference to ourselves in this closure.
139 download_continuation_ = base::Closure();
75 } else { 140 } else {
76 Error(error::kTempFileError); 141 Error(error::kDownloadInterrupted);
77 } 142 }
78 } 143 }
79 144
80 // The downloader runs on the UI thread. 145 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)); 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(
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( 160 GetMD5SumOfFile(
224 download_path.Pass(), 161 image_path_,
225 0, 162 0,
226 0, 163 0,
227 kProgressComplete, 164 kProgressComplete,
228 base::Bind(&WriteFromUrlOperation::VerifyDownloadCompare, this)); 165 base::Bind(
166 &WriteFromUrlOperation::VerifyDownloadCompare, this, continuation));
229 } 167 }
230 168
231 void WriteFromUrlOperation::VerifyDownloadCompare( 169 void WriteFromUrlOperation::VerifyDownloadCompare(
232 scoped_ptr<std::string> download_hash) { 170 const base::Closure& continuation,
171 const std::string& download_hash) {
233 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 172 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
234 if (*download_hash != hash_) { 173 if (download_hash != hash_) {
235 Error(error::kDownloadHashError); 174 Error(error::kDownloadHashError);
236 return; 175 return;
237 } 176 }
238 177
239 BrowserThread::PostTask( 178 BrowserThread::PostTask(
240 BrowserThread::FILE, 179 BrowserThread::FILE,
241 FROM_HERE, 180 FROM_HERE,
242 base::Bind(&WriteFromUrlOperation::VerifyDownloadComplete, this)); 181 base::Bind(
182 &WriteFromUrlOperation::VerifyDownloadComplete, this, continuation));
243 } 183 }
244 184
245 void WriteFromUrlOperation::VerifyDownloadComplete() { 185 void WriteFromUrlOperation::VerifyDownloadComplete(
186 const base::Closure& continuation) {
246 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 187 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
247 if (IsCancelled()) { 188 if (IsCancelled()) {
248 return; 189 return;
249 } 190 }
250 191
251 DVLOG(1) << "Download verification complete.";
252
253 SetProgress(kProgressComplete); 192 SetProgress(kProgressComplete);
254 193
255 scoped_ptr<base::FilePath> download_path(new base::FilePath(download_path_)); 194 continuation.Run();
256 UnzipStart(download_path.Pass());
257 } 195 }
258 196
259 } // namespace image_writer 197 } // namespace image_writer
260 } // namespace extensions 198 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698