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_->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 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 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 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 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 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 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 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 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 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