• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
WebstoreInstallHelper(Delegate * delegate,const std::string & id,const std::string & manifest,const std::string & icon_data,const GURL & icon_url,net::URLRequestContextGetter * context_getter)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 
~WebstoreInstallHelper()47 WebstoreInstallHelper::~WebstoreInstallHelper() {}
48 
Start()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 
StartWorkOnIOThread()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_->StartBatchMode();
79 
80   if (!icon_base64_data_.empty())
81     utility_host_->Send(
82         new ChromeUtilityMsg_DecodeImageBase64(icon_base64_data_));
83 
84   utility_host_->Send(new ChromeUtilityMsg_ParseJSON(manifest_));
85 }
86 
OnURLFetchComplete(const net::URLFetcher * source)87 void WebstoreInstallHelper::OnURLFetchComplete(
88     const net::URLFetcher* source) {
89   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
90   CHECK(source == url_fetcher_.get());
91   if (source->GetStatus().status() != net::URLRequestStatus::SUCCESS ||
92       source->GetResponseCode() != 200) {
93     BrowserThread::PostTask(
94         BrowserThread::IO,
95         FROM_HERE,
96         base::Bind(&WebstoreInstallHelper::OnDecodeImageFailed, this));
97   } else {
98     std::string response_data;
99     source->GetResponseAsString(&response_data);
100     fetched_icon_data_.insert(fetched_icon_data_.begin(),
101                               response_data.begin(),
102                               response_data.end());
103     BrowserThread::PostTask(
104         BrowserThread::IO,
105         FROM_HERE,
106         base::Bind(&WebstoreInstallHelper::StartFetchedImageDecode, this));
107   }
108   url_fetcher_.reset();
109 }
110 
StartFetchedImageDecode()111 void WebstoreInstallHelper::StartFetchedImageDecode() {
112   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
113   CHECK(utility_host_.get());
114   utility_host_->Send(new ChromeUtilityMsg_DecodeImage(fetched_icon_data_));
115 }
116 
117 
OnMessageReceived(const IPC::Message & message)118 bool WebstoreInstallHelper::OnMessageReceived(const IPC::Message& message) {
119   bool handled = true;
120   IPC_BEGIN_MESSAGE_MAP(WebstoreInstallHelper, message)
121     IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_DecodeImage_Succeeded,
122                         OnDecodeImageSucceeded)
123     IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_DecodeImage_Failed,
124                         OnDecodeImageFailed)
125     IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Succeeded,
126                         OnJSONParseSucceeded)
127     IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Failed,
128                         OnJSONParseFailed)
129     IPC_MESSAGE_UNHANDLED(handled = false)
130   IPC_END_MESSAGE_MAP()
131   return handled;
132 }
133 
134 
OnDecodeImageSucceeded(const SkBitmap & decoded_image)135 void WebstoreInstallHelper::OnDecodeImageSucceeded(
136     const SkBitmap& decoded_image) {
137   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
138   icon_ = decoded_image;
139   icon_decode_complete_ = true;
140   ReportResultsIfComplete();
141 }
142 
OnDecodeImageFailed()143 void WebstoreInstallHelper::OnDecodeImageFailed() {
144   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
145   icon_decode_complete_ = true;
146   error_ = kImageDecodeError;
147   parse_error_ = Delegate::ICON_ERROR;
148   ReportResultsIfComplete();
149 }
150 
OnJSONParseSucceeded(const base::ListValue & wrapper)151 void WebstoreInstallHelper::OnJSONParseSucceeded(
152     const base::ListValue& wrapper) {
153   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
154   manifest_parse_complete_ = true;
155   const Value* value = NULL;
156   CHECK(wrapper.Get(0, &value));
157   if (value->IsType(Value::TYPE_DICTIONARY)) {
158     parsed_manifest_.reset(
159         static_cast<const DictionaryValue*>(value)->DeepCopy());
160   } else {
161     parse_error_ = Delegate::MANIFEST_ERROR;
162   }
163   ReportResultsIfComplete();
164 }
165 
OnJSONParseFailed(const std::string & error_message)166 void WebstoreInstallHelper::OnJSONParseFailed(
167     const std::string& error_message) {
168   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
169   manifest_parse_complete_ = true;
170   error_ = error_message;
171   parse_error_ = Delegate::MANIFEST_ERROR;
172   ReportResultsIfComplete();
173 }
174 
ReportResultsIfComplete()175 void WebstoreInstallHelper::ReportResultsIfComplete() {
176   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
177 
178   if (!icon_decode_complete_ || !manifest_parse_complete_)
179     return;
180 
181   // The utility_host_ will take care of deleting itself after this call.
182   if (utility_host_.get()) {
183     utility_host_->EndBatchMode();
184     utility_host_.reset();
185   }
186 
187   BrowserThread::PostTask(
188       BrowserThread::UI,
189       FROM_HERE,
190       base::Bind(&WebstoreInstallHelper::ReportResultFromUIThread, this));
191 }
192 
ReportResultFromUIThread()193 void WebstoreInstallHelper::ReportResultFromUIThread() {
194   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
195   if (error_.empty() && parsed_manifest_)
196     delegate_->OnWebstoreParseSuccess(id_, icon_, parsed_manifest_.release());
197   else
198     delegate_->OnWebstoreParseFailure(id_, parse_error_, error_);
199 }
200 
201 }  // namespace extensions
202