• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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