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