Home | History | Annotate | Download | only in extensions
      1 // Copyright (c) 2012 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 "chrome/browser/extensions/webstore_install_helper.h"
      6 
      7 #include <string>
      8 
      9 #include "base/bind.h"
     10 #include "base/values.h"
     11 #include "chrome/common/chrome_utility_messages.h"
     12 #include "chrome/common/extensions/chrome_utility_extensions_messages.h"
     13 #include "content/public/browser/browser_thread.h"
     14 #include "content/public/browser/utility_process_host.h"
     15 #include "net/base/load_flags.h"
     16 #include "net/url_request/url_fetcher.h"
     17 #include "net/url_request/url_request_context_getter.h"
     18 #include "net/url_request/url_request_status.h"
     19 
     20 using content::BrowserThread;
     21 using content::UtilityProcessHost;
     22 
     23 namespace {
     24 
     25 const char kImageDecodeError[] = "Image decode failed";
     26 
     27 }  // namespace
     28 
     29 namespace extensions {
     30 
     31 WebstoreInstallHelper::WebstoreInstallHelper(
     32     Delegate* delegate,
     33     const std::string& id,
     34     const std::string& manifest,
     35     const std::string& icon_data,
     36     const GURL& icon_url,
     37     net::URLRequestContextGetter* context_getter)
     38     : delegate_(delegate),
     39       id_(id),
     40       manifest_(manifest),
     41       icon_base64_data_(icon_data),
     42       icon_url_(icon_url),
     43       context_getter_(context_getter),
     44       icon_decode_complete_(false),
     45       manifest_parse_complete_(false),
     46       parse_error_(Delegate::UNKNOWN_ERROR) {}
     47 
     48 WebstoreInstallHelper::~WebstoreInstallHelper() {}
     49 
     50 void WebstoreInstallHelper::Start() {
     51   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     52   CHECK(icon_base64_data_.empty() || icon_url_.is_empty());
     53 
     54   if (icon_base64_data_.empty() && icon_url_.is_empty())
     55     icon_decode_complete_ = true;
     56 
     57   BrowserThread::PostTask(
     58       BrowserThread::IO,
     59       FROM_HERE,
     60       base::Bind(&WebstoreInstallHelper::StartWorkOnIOThread, this));
     61 
     62   if (!icon_url_.is_empty()) {
     63     CHECK(context_getter_);
     64     url_fetcher_.reset(net::URLFetcher::Create(
     65         icon_url_, net::URLFetcher::GET, this));
     66     url_fetcher_->SetRequestContext(context_getter_);
     67     url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
     68                                net::LOAD_DO_NOT_SEND_COOKIES);
     69 
     70     url_fetcher_->Start();
     71     // We'll get called back in OnURLFetchComplete.
     72   }
     73 }
     74 
     75 void WebstoreInstallHelper::StartWorkOnIOThread() {
     76   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     77   utility_host_ = UtilityProcessHost::Create(
     78       this, base::MessageLoopProxy::current().get())->AsWeakPtr();
     79   utility_host_->StartBatchMode();
     80 
     81   if (!icon_base64_data_.empty())
     82     utility_host_->Send(
     83         new ChromeUtilityMsg_DecodeImageBase64(icon_base64_data_));
     84 
     85   utility_host_->Send(new ChromeUtilityMsg_ParseJSON(manifest_));
     86 }
     87 
     88 void WebstoreInstallHelper::OnURLFetchComplete(
     89     const net::URLFetcher* source) {
     90   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     91   CHECK(source == url_fetcher_.get());
     92   int response_code =
     93       source->GetStatus().is_success() ? source->GetResponseCode() : 0;
     94   if (!source->GetStatus().is_success() ||
     95       response_code / 100 == 4 || response_code / 100 == 5) {
     96     BrowserThread::PostTask(
     97         BrowserThread::IO,
     98         FROM_HERE,
     99         base::Bind(&WebstoreInstallHelper::OnDecodeImageFailed, this));
    100   } else {
    101     std::string response_data;
    102     source->GetResponseAsString(&response_data);
    103     fetched_icon_data_.insert(fetched_icon_data_.begin(),
    104                               response_data.begin(),
    105                               response_data.end());
    106     BrowserThread::PostTask(
    107         BrowserThread::IO,
    108         FROM_HERE,
    109         base::Bind(&WebstoreInstallHelper::StartFetchedImageDecode, this));
    110   }
    111   url_fetcher_.reset();
    112 }
    113 
    114 void WebstoreInstallHelper::StartFetchedImageDecode() {
    115   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    116   CHECK(utility_host_.get());
    117   utility_host_->Send(new ChromeUtilityMsg_DecodeImage(fetched_icon_data_,
    118                                                        false));
    119 }
    120 
    121 
    122 bool WebstoreInstallHelper::OnMessageReceived(const IPC::Message& message) {
    123   bool handled = true;
    124   IPC_BEGIN_MESSAGE_MAP(WebstoreInstallHelper, message)
    125     IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_DecodeImage_Succeeded,
    126                         OnDecodeImageSucceeded)
    127     IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_DecodeImage_Failed,
    128                         OnDecodeImageFailed)
    129     IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Succeeded,
    130                         OnJSONParseSucceeded)
    131     IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Failed,
    132                         OnJSONParseFailed)
    133     IPC_MESSAGE_UNHANDLED(handled = false)
    134   IPC_END_MESSAGE_MAP()
    135   return handled;
    136 }
    137 
    138 
    139 void WebstoreInstallHelper::OnDecodeImageSucceeded(
    140     const SkBitmap& decoded_image) {
    141   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    142   icon_ = decoded_image;
    143   icon_decode_complete_ = true;
    144   ReportResultsIfComplete();
    145 }
    146 
    147 void WebstoreInstallHelper::OnDecodeImageFailed() {
    148   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    149   icon_decode_complete_ = true;
    150   error_ = kImageDecodeError;
    151   parse_error_ = Delegate::ICON_ERROR;
    152   ReportResultsIfComplete();
    153 }
    154 
    155 void WebstoreInstallHelper::OnJSONParseSucceeded(
    156     const base::ListValue& wrapper) {
    157   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    158   manifest_parse_complete_ = true;
    159   const base::Value* value = NULL;
    160   CHECK(wrapper.Get(0, &value));
    161   if (value->IsType(base::Value::TYPE_DICTIONARY)) {
    162     parsed_manifest_.reset(
    163         static_cast<const base::DictionaryValue*>(value)->DeepCopy());
    164   } else {
    165     parse_error_ = Delegate::MANIFEST_ERROR;
    166   }
    167   ReportResultsIfComplete();
    168 }
    169 
    170 void WebstoreInstallHelper::OnJSONParseFailed(
    171     const std::string& error_message) {
    172   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    173   manifest_parse_complete_ = true;
    174   error_ = error_message;
    175   parse_error_ = Delegate::MANIFEST_ERROR;
    176   ReportResultsIfComplete();
    177 }
    178 
    179 void WebstoreInstallHelper::ReportResultsIfComplete() {
    180   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    181 
    182   if (!icon_decode_complete_ || !manifest_parse_complete_)
    183     return;
    184 
    185   // The utility_host_ will take care of deleting itself after this call.
    186   if (utility_host_.get()) {
    187     utility_host_->EndBatchMode();
    188     utility_host_.reset();
    189   }
    190 
    191   BrowserThread::PostTask(
    192       BrowserThread::UI,
    193       FROM_HERE,
    194       base::Bind(&WebstoreInstallHelper::ReportResultFromUIThread, this));
    195 }
    196 
    197 void WebstoreInstallHelper::ReportResultFromUIThread() {
    198   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    199   if (error_.empty() && parsed_manifest_)
    200     delegate_->OnWebstoreParseSuccess(id_, icon_, parsed_manifest_.release());
    201   else
    202     delegate_->OnWebstoreParseFailure(id_, parse_error_, error_);
    203 }
    204 
    205 }  // namespace extensions
    206