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