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/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 12namespace extensions { 13namespace image_writer { 14 15using content::BrowserThread; 16 17WriteFromUrlOperation::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 30WriteFromUrlOperation::~WriteFromUrlOperation() { 31} 32 33void 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 53void 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 74void 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 100void WriteFromUrlOperation::DestroyUrlFetcher() { url_fetcher_.reset(); } 101 102void WriteFromUrlOperation::OnURLFetchUploadProgress( 103 const net::URLFetcher* source, 104 int64 current, 105 int64 total) { 106 // No-op 107} 108 109void 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 124void 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 139void 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 163void 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 179void 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