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