Home | History | Annotate | Download | only in image_writer_private
      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 
     12 namespace extensions {
     13 namespace image_writer {
     14 
     15 using content::BrowserThread;
     16 
     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 
     30 WriteFromUrlOperation::~WriteFromUrlOperation() {
     31 }
     32 
     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 
     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 
     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 
    100 void WriteFromUrlOperation::DestroyUrlFetcher() { url_fetcher_.reset(); }
    101 
    102 void WriteFromUrlOperation::OnURLFetchUploadProgress(
    103     const net::URLFetcher* source,
    104     int64 current,
    105     int64 total) {
    106   // No-op
    107 }
    108 
    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 
    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 
    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 
    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 
    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