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/files/file_util.h"
6 #include "chrome/browser/extensions/api/image_writer_private/error_messages.h"
7 #include "chrome/browser/extensions/api/image_writer_private/operation_manager.h"
8 #include "chrome/browser/extensions/api/image_writer_private/write_from_url_operation.h"
9 #include "content/public/browser/browser_thread.h"
10 #include "net/url_request/url_fetcher.h"
11
12 namespace extensions {
13 namespace image_writer {
14
15 using content::BrowserThread;
16
WriteFromUrlOperation(base::WeakPtr<OperationManager> manager,const ExtensionId & extension_id,net::URLRequestContextGetter * request_context,GURL url,const std::string & hash,const std::string & device_path)17 WriteFromUrlOperation::WriteFromUrlOperation(
18 base::WeakPtr<OperationManager> manager,
19 const ExtensionId& extension_id,
20 net::URLRequestContextGetter* request_context,
21 GURL url,
22 const std::string& hash,
23 const std::string& device_path)
24 : Operation(manager, extension_id, device_path),
25 request_context_(request_context),
26 url_(url),
27 hash_(hash),
28 download_continuation_() {}
29
~WriteFromUrlOperation()30 WriteFromUrlOperation::~WriteFromUrlOperation() {
31 }
32
StartImpl()33 void WriteFromUrlOperation::StartImpl() {
34 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
35
36 GetDownloadTarget(base::Bind(
37 &WriteFromUrlOperation::Download,
38 this,
39 base::Bind(
40 &WriteFromUrlOperation::VerifyDownload,
41 this,
42 base::Bind(
43 &WriteFromUrlOperation::Unzip,
44 this,
45 base::Bind(&WriteFromUrlOperation::Write,
46 this,
47 base::Bind(&WriteFromUrlOperation::VerifyWrite,
48 this,
49 base::Bind(&WriteFromUrlOperation::Finish,
50 this)))))));
51 }
52
GetDownloadTarget(const base::Closure & continuation)53 void WriteFromUrlOperation::GetDownloadTarget(
54 const base::Closure& continuation) {
55 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
56 if (IsCancelled()) {
57 return;
58 }
59
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 }
70
71 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, continuation);
72 }
73
Download(const base::Closure & continuation)74 void WriteFromUrlOperation::Download(const base::Closure& continuation) {
75 DCHECK_CURRENTLY_ON(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
DestroyUrlFetcher()100 void WriteFromUrlOperation::DestroyUrlFetcher() { url_fetcher_.reset(); }
101
OnURLFetchUploadProgress(const net::URLFetcher * source,int64 current,int64 total)102 void WriteFromUrlOperation::OnURLFetchUploadProgress(
103 const net::URLFetcher* source,
104 int64 current,
105 int64 total) {
106 // No-op
107 }
108
OnURLFetchDownloadProgress(const net::URLFetcher * source,int64 current,int64 total)109 void WriteFromUrlOperation::OnURLFetchDownloadProgress(
110 const net::URLFetcher* source,
111 int64 current,
112 int64 total) {
113 DCHECK_CURRENTLY_ON(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
OnURLFetchComplete(const net::URLFetcher * source)124 void WriteFromUrlOperation::OnURLFetchComplete(const net::URLFetcher* source) {
125 DCHECK_CURRENTLY_ON(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();
134 } else {
135 Error(error::kDownloadInterrupted);
136 }
137 }
138
VerifyDownload(const base::Closure & continuation)139 void WriteFromUrlOperation::VerifyDownload(const base::Closure& continuation) {
140 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
141
142 if (IsCancelled()) {
143 return;
144 }
145
146 // Skip verify if no hash.
147 if (hash_.empty()) {
148 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, continuation);
149 return;
150 }
151
152 SetStage(image_writer_api::STAGE_VERIFYDOWNLOAD);
153
154 GetMD5SumOfFile(
155 image_path_,
156 0,
157 0,
158 kProgressComplete,
159 base::Bind(
160 &WriteFromUrlOperation::VerifyDownloadCompare, this, continuation));
161 }
162
VerifyDownloadCompare(const base::Closure & continuation,const std::string & download_hash)163 void WriteFromUrlOperation::VerifyDownloadCompare(
164 const base::Closure& continuation,
165 const std::string& download_hash) {
166 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
167 if (download_hash != hash_) {
168 Error(error::kDownloadHashError);
169 return;
170 }
171
172 BrowserThread::PostTask(
173 BrowserThread::FILE,
174 FROM_HERE,
175 base::Bind(
176 &WriteFromUrlOperation::VerifyDownloadComplete, this, continuation));
177 }
178
VerifyDownloadComplete(const base::Closure & continuation)179 void WriteFromUrlOperation::VerifyDownloadComplete(
180 const base::Closure& continuation) {
181 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
182 if (IsCancelled()) {
183 return;
184 }
185
186 SetProgress(kProgressComplete);
187 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, continuation);
188 }
189
190 } // namespace image_writer
191 } // namespace extensions
192