| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/extensions/extension_webstore_private_api.h" | 5 #include "chrome/browser/extensions/extension_webstore_private_api.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/scoped_temp_dir.h" | 10 #include "base/scoped_temp_dir.h" |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 #include "chrome/common/chrome_notification_types.h" | 23 #include "chrome/common/chrome_notification_types.h" |
| 24 #include "chrome/common/chrome_switches.h" | 24 #include "chrome/common/chrome_switches.h" |
| 25 #include "chrome/common/chrome_utility_messages.h" | 25 #include "chrome/common/chrome_utility_messages.h" |
| 26 #include "chrome/common/extensions/extension_constants.h" | 26 #include "chrome/common/extensions/extension_constants.h" |
| 27 #include "chrome/common/extensions/extension_error_utils.h" | 27 #include "chrome/common/extensions/extension_error_utils.h" |
| 28 #include "chrome/common/extensions/extension_l10n_util.h" | 28 #include "chrome/common/extensions/extension_l10n_util.h" |
| 29 #include "chrome/common/net/gaia/gaia_constants.h" | 29 #include "chrome/common/net/gaia/gaia_constants.h" |
| 30 #include "content/browser/tab_contents/tab_contents.h" | 30 #include "content/browser/tab_contents/tab_contents.h" |
| 31 #include "content/common/notification_details.h" | 31 #include "content/common/notification_details.h" |
| 32 #include "content/common/notification_source.h" | 32 #include "content/common/notification_source.h" |
| 33 #include "content/common/url_fetcher.h" |
| 33 #include "grit/chromium_strings.h" | 34 #include "grit/chromium_strings.h" |
| 34 #include "grit/generated_resources.h" | 35 #include "grit/generated_resources.h" |
| 36 #include "net/url_request/url_request_status.h" |
| 35 #include "ui/base/l10n/l10n_util.h" | 37 #include "ui/base/l10n/l10n_util.h" |
| 36 | 38 |
| 37 namespace { | 39 namespace { |
| 38 | 40 |
| 39 const char kAppInstallBubbleKey[] = "appInstallBubble"; | 41 const char kAppInstallBubbleKey[] = "appInstallBubble"; |
| 40 const char kIconDataKey[] = "iconData"; | 42 const char kIconDataKey[] = "iconData"; |
| 43 const char kIconUrlKey[] = "iconUrl"; |
| 41 const char kIdKey[] = "id"; | 44 const char kIdKey[] = "id"; |
| 42 const char kLocalizedNameKey[] = "localizedName"; | 45 const char kLocalizedNameKey[] = "localizedName"; |
| 43 const char kLoginKey[] = "login"; | 46 const char kLoginKey[] = "login"; |
| 44 const char kManifestKey[] = "manifest"; | 47 const char kManifestKey[] = "manifest"; |
| 45 const char kTokenKey[] = "token"; | 48 const char kTokenKey[] = "token"; |
| 46 | 49 |
| 50 const char kCannotSpecifyIconDataAndUrlError[] = |
| 51 "You cannot specify both icon data and an icon url"; |
| 47 const char kImageDecodeError[] = "Image decode failed"; | 52 const char kImageDecodeError[] = "Image decode failed"; |
| 53 const char kInvalidIconUrlError[] = "Invalid icon url"; |
| 48 const char kInvalidIdError[] = "Invalid id"; | 54 const char kInvalidIdError[] = "Invalid id"; |
| 49 const char kInvalidManifestError[] = "Invalid manifest"; | 55 const char kInvalidManifestError[] = "Invalid manifest"; |
| 50 const char kNoPreviousBeginInstallError[] = | 56 const char kNoPreviousBeginInstallError[] = |
| 51 "* does not match a previous call to beginInstall"; | 57 "* does not match a previous call to beginInstall"; |
| 52 const char kUserCancelledError[] = "User cancelled install"; | 58 const char kUserCancelledError[] = "User cancelled install"; |
| 53 const char kUserGestureRequiredError[] = | 59 const char kUserGestureRequiredError[] = |
| 54 "This function must be called during a user gesture"; | 60 "This function must be called during a user gesture"; |
| 55 | 61 |
| 56 ProfileSyncService* test_sync_service = NULL; | 62 ProfileSyncService* test_sync_service = NULL; |
| 57 BrowserSignin* test_signin = NULL; | 63 BrowserSignin* test_signin = NULL; |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 145 } | 151 } |
| 146 | 152 |
| 147 // This gets cleared in CrxInstaller::ConfirmInstall(). TODO(asargent) - in | 153 // This gets cleared in CrxInstaller::ConfirmInstall(). TODO(asargent) - in |
| 148 // the future we may also want to add time-based expiration, where a whitelist | 154 // the future we may also want to add time-based expiration, where a whitelist |
| 149 // entry is only valid for some number of minutes. | 155 // entry is only valid for some number of minutes. |
| 150 CrxInstaller::SetWhitelistedInstallId(id); | 156 CrxInstaller::SetWhitelistedInstallId(id); |
| 151 return true; | 157 return true; |
| 152 } | 158 } |
| 153 | 159 |
| 154 // This is a class to help BeginInstallWithManifestFunction manage sending | 160 // This is a class to help BeginInstallWithManifestFunction manage sending |
| 155 // JSON manifests and base64-encoded icon data to the utility process for | 161 // work to the utility process for parsing manifests and fetching/decoding |
| 156 // parsing. | 162 // icon data. |
| 157 class SafeBeginInstallHelper : public UtilityProcessHost::Client { | 163 class SafeBeginInstallHelper : public UtilityProcessHost::Client, |
| 164 public URLFetcher::Delegate { |
| 158 public: | 165 public: |
| 166 // Only one of icon_data or icon_url should be non-empty. If icon_url is |
| 167 // non-empty, context_getter should be filled in, but otherwise NULL. |
| 159 SafeBeginInstallHelper(BeginInstallWithManifestFunction* client, | 168 SafeBeginInstallHelper(BeginInstallWithManifestFunction* client, |
| 169 const std::string& manifest, |
| 160 const std::string& icon_data, | 170 const std::string& icon_data, |
| 161 const std::string& manifest) | 171 const GURL& icon_url, |
| 172 net::URLRequestContextGetter* context_getter) |
| 162 : client_(client), | 173 : client_(client), |
| 163 icon_data_(icon_data), | |
| 164 manifest_(manifest), | 174 manifest_(manifest), |
| 175 icon_base64_data_(icon_data), |
| 176 icon_url_(icon_url), |
| 177 context_getter_(context_getter), |
| 165 utility_host_(NULL), | 178 utility_host_(NULL), |
| 166 icon_decode_complete_(false), | 179 icon_decode_complete_(false), |
| 167 manifest_parse_complete_(false), | 180 manifest_parse_complete_(false), |
| 168 parse_error_(BeginInstallWithManifestFunction::UNKNOWN_ERROR) {} | 181 parse_error_(BeginInstallWithManifestFunction::UNKNOWN_ERROR) {} |
| 169 | 182 |
| 170 void Start() { | 183 void Start() { |
| 171 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 184 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 185 CHECK(icon_base64_data_.empty() || icon_url_.is_empty()); |
| 186 |
| 187 if (icon_base64_data_.empty() && icon_url_.is_empty()) |
| 188 icon_decode_complete_ = true; |
| 189 |
| 172 BrowserThread::PostTask( | 190 BrowserThread::PostTask( |
| 173 BrowserThread::IO, | 191 BrowserThread::IO, |
| 174 FROM_HERE, | 192 FROM_HERE, |
| 175 NewRunnableMethod(this, | 193 NewRunnableMethod(this, |
| 176 &SafeBeginInstallHelper::StartWorkOnIOThread)); | 194 &SafeBeginInstallHelper::StartWorkOnIOThread)); |
| 195 |
| 196 if (!icon_url_.is_empty()) { |
| 197 CHECK(context_getter_); |
| 198 url_fetcher_.reset(new URLFetcher(icon_url_, URLFetcher::GET, this)); |
| 199 url_fetcher_->set_request_context(context_getter_); |
| 200 |
| 201 url_fetcher_->Start(); |
| 202 // We'll get called back in OnURLFetchComplete. |
| 203 } |
| 177 } | 204 } |
| 178 | 205 |
| 179 void StartWorkOnIOThread() { | 206 void StartWorkOnIOThread() { |
| 180 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 207 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 181 utility_host_ = new UtilityProcessHost(this, BrowserThread::IO); | 208 utility_host_ = new UtilityProcessHost(this, BrowserThread::IO); |
| 182 utility_host_->StartBatchMode(); | 209 utility_host_->StartBatchMode(); |
| 183 if (icon_data_.empty()) | 210 |
| 184 icon_decode_complete_ = true; | 211 if (!icon_base64_data_.empty()) |
| 185 else | 212 utility_host_->Send( |
| 186 utility_host_->Send(new ChromeUtilityMsg_DecodeImageBase64(icon_data_)); | 213 new ChromeUtilityMsg_DecodeImageBase64(icon_base64_data_)); |
| 214 |
| 187 utility_host_->Send(new ChromeUtilityMsg_ParseJSON(manifest_)); | 215 utility_host_->Send(new ChromeUtilityMsg_ParseJSON(manifest_)); |
| 188 } | 216 } |
| 189 | 217 |
| 218 // Implementing the URLFetcher::Delegate interface. |
| 219 virtual void OnURLFetchComplete(const URLFetcher* source) OVERRIDE { |
| 220 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 221 CHECK(source == url_fetcher_.get()); |
| 222 if (source->status().status() != net::URLRequestStatus::SUCCESS || |
| 223 source->response_code() != 200) { |
| 224 BrowserThread::PostTask( |
| 225 BrowserThread::IO, |
| 226 FROM_HERE, |
| 227 NewRunnableMethod(this, |
| 228 &SafeBeginInstallHelper::OnDecodeImageFailed)); |
| 229 } else { |
| 230 std::string response_data; |
| 231 source->GetResponseAsString(&response_data); |
| 232 fetched_icon_data_.insert(fetched_icon_data_.begin(), |
| 233 response_data.begin(), |
| 234 response_data.end()); |
| 235 BrowserThread::PostTask( |
| 236 BrowserThread::IO, |
| 237 FROM_HERE, |
| 238 NewRunnableMethod(this, |
| 239 &SafeBeginInstallHelper::StartFetchedImageDecode)); |
| 240 } |
| 241 url_fetcher_.reset(); |
| 242 } |
| 243 |
| 244 void StartFetchedImageDecode() { |
| 245 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 246 CHECK(utility_host_); |
| 247 utility_host_->Send(new ChromeUtilityMsg_DecodeImage(fetched_icon_data_)); |
| 248 } |
| 249 |
| 190 // Implementing pieces of the UtilityProcessHost::Client interface. | 250 // Implementing pieces of the UtilityProcessHost::Client interface. |
| 191 virtual bool OnMessageReceived(const IPC::Message& message) { | 251 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { |
| 192 bool handled = true; | 252 bool handled = true; |
| 193 IPC_BEGIN_MESSAGE_MAP(SafeBeginInstallHelper, message) | 253 IPC_BEGIN_MESSAGE_MAP(SafeBeginInstallHelper, message) |
| 194 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_DecodeImage_Succeeded, | 254 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_DecodeImage_Succeeded, |
| 195 OnDecodeImageSucceeded) | 255 OnDecodeImageSucceeded) |
| 196 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_DecodeImage_Failed, | 256 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_DecodeImage_Failed, |
| 197 OnDecodeImageFailed) | 257 OnDecodeImageFailed) |
| 198 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Succeeded, | 258 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Succeeded, |
| 199 OnJSONParseSucceeded) | 259 OnJSONParseSucceeded) |
| 200 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Failed, | 260 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Failed, |
| 201 OnJSONParseFailed) | 261 OnJSONParseFailed) |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 265 else | 325 else |
| 266 client_->OnParseFailure(parse_error_, error_); | 326 client_->OnParseFailure(parse_error_, error_); |
| 267 } | 327 } |
| 268 | 328 |
| 269 private: | 329 private: |
| 270 ~SafeBeginInstallHelper() {} | 330 ~SafeBeginInstallHelper() {} |
| 271 | 331 |
| 272 // The client who we'll report results back to. | 332 // The client who we'll report results back to. |
| 273 BeginInstallWithManifestFunction* client_; | 333 BeginInstallWithManifestFunction* client_; |
| 274 | 334 |
| 275 // The data to parse. | 335 // The manifest to parse. |
| 276 std::string icon_data_; | |
| 277 std::string manifest_; | 336 std::string manifest_; |
| 278 | 337 |
| 338 // Only one of these should be non-empty. If |icon_base64_data_| is non-emtpy, |
| 339 // it's a base64-encoded string that needs to be parsed into an SkBitmap. If |
| 340 // |icon_url_| is non-empty, it needs to be fetched and decoded into an |
| 341 // SkBitmap. |
| 342 std::string icon_base64_data_; |
| 343 GURL icon_url_; |
| 344 std::vector<unsigned char> fetched_icon_data_; |
| 345 |
| 346 // For fetching the icon, if needed. |
| 347 scoped_ptr<URLFetcher> url_fetcher_; |
| 348 net::URLRequestContextGetter* context_getter_; // Only usable on UI thread. |
| 349 |
| 279 UtilityProcessHost* utility_host_; | 350 UtilityProcessHost* utility_host_; |
| 280 | 351 |
| 281 // Flags for whether we're done doing icon decoding and manifest parsing. | 352 // Flags for whether we're done doing icon decoding and manifest parsing. |
| 282 bool icon_decode_complete_; | 353 bool icon_decode_complete_; |
| 283 bool manifest_parse_complete_; | 354 bool manifest_parse_complete_; |
| 284 | 355 |
| 285 // The results of succesful decoding/parsing. | 356 // The results of succesful decoding/parsing. |
| 286 SkBitmap icon_; | 357 SkBitmap icon_; |
| 287 scoped_ptr<DictionaryValue> parsed_manifest_; | 358 scoped_ptr<DictionaryValue> parsed_manifest_; |
| 288 | 359 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 317 | 388 |
| 318 EXTENSION_FUNCTION_VALIDATE(details->GetString(kIdKey, &id_)); | 389 EXTENSION_FUNCTION_VALIDATE(details->GetString(kIdKey, &id_)); |
| 319 if (!Extension::IdIsValid(id_)) { | 390 if (!Extension::IdIsValid(id_)) { |
| 320 SetResult(INVALID_ID); | 391 SetResult(INVALID_ID); |
| 321 error_ = kInvalidIdError; | 392 error_ = kInvalidIdError; |
| 322 return false; | 393 return false; |
| 323 } | 394 } |
| 324 | 395 |
| 325 EXTENSION_FUNCTION_VALIDATE(details->GetString(kManifestKey, &manifest_)); | 396 EXTENSION_FUNCTION_VALIDATE(details->GetString(kManifestKey, &manifest_)); |
| 326 | 397 |
| 398 if (details->HasKey(kIconDataKey) && details->HasKey(kIconUrlKey)) { |
| 399 SetResult(ICON_ERROR); |
| 400 error_ = kCannotSpecifyIconDataAndUrlError; |
| 401 return false; |
| 402 } |
| 403 |
| 327 if (details->HasKey(kIconDataKey)) | 404 if (details->HasKey(kIconDataKey)) |
| 328 EXTENSION_FUNCTION_VALIDATE(details->GetString(kIconDataKey, &icon_data_)); | 405 EXTENSION_FUNCTION_VALIDATE(details->GetString(kIconDataKey, &icon_data_)); |
| 329 | 406 |
| 407 GURL icon_url; |
| 408 if (details->HasKey(kIconUrlKey)) { |
| 409 std::string tmp_url; |
| 410 EXTENSION_FUNCTION_VALIDATE(details->GetString(kIconUrlKey, &tmp_url)); |
| 411 icon_url = source_url().Resolve(tmp_url); |
| 412 if (!icon_url.is_valid()) { |
| 413 SetResult(INVALID_ICON_URL); |
| 414 error_ = kInvalidIconUrlError; |
| 415 return false; |
| 416 } |
| 417 } |
| 418 |
| 330 if (details->HasKey(kLocalizedNameKey)) | 419 if (details->HasKey(kLocalizedNameKey)) |
| 331 EXTENSION_FUNCTION_VALIDATE(details->GetString(kLocalizedNameKey, | 420 EXTENSION_FUNCTION_VALIDATE(details->GetString(kLocalizedNameKey, |
| 332 &localized_name_)); | 421 &localized_name_)); |
| 333 | 422 |
| 334 if (details->HasKey(kAppInstallBubbleKey)) | 423 if (details->HasKey(kAppInstallBubbleKey)) |
| 335 EXTENSION_FUNCTION_VALIDATE(details->GetBoolean( | 424 EXTENSION_FUNCTION_VALIDATE(details->GetBoolean( |
| 336 kAppInstallBubbleKey, &use_app_installed_bubble_)); | 425 kAppInstallBubbleKey, &use_app_installed_bubble_)); |
| 337 | 426 |
| 338 scoped_refptr<SafeBeginInstallHelper> helper = | 427 net::URLRequestContextGetter* context_getter = NULL; |
| 339 new SafeBeginInstallHelper(this, icon_data_, manifest_); | 428 if (!icon_url.is_empty()) |
| 340 // The helper will call us back via OnParseSucces or OnParseFailure. | 429 context_getter = profile()->GetRequestContext(); |
| 430 |
| 431 scoped_refptr<SafeBeginInstallHelper> helper = new SafeBeginInstallHelper( |
| 432 this, manifest_, icon_data_, icon_url, context_getter); |
| 433 |
| 434 // The helper will call us back via OnParseSuccess or OnParseFailure. |
| 341 helper->Start(); | 435 helper->Start(); |
| 342 | 436 |
| 343 // Matched with a Release in OnSuccess/OnFailure. | 437 // Matched with a Release in OnParseSuccess/OnParseFailure. |
| 344 AddRef(); | 438 AddRef(); |
| 345 | 439 |
| 346 // The response is sent asynchronously in OnSuccess/OnFailure. | 440 // The response is sent asynchronously in OnParseSuccess/OnParseFailure. |
| 347 return true; | 441 return true; |
| 348 } | 442 } |
| 349 | 443 |
| 350 | 444 |
| 351 void BeginInstallWithManifestFunction::SetResult(ResultCode code) { | 445 void BeginInstallWithManifestFunction::SetResult(ResultCode code) { |
| 352 switch (code) { | 446 switch (code) { |
| 353 case ERROR_NONE: | 447 case ERROR_NONE: |
| 354 result_.reset(Value::CreateStringValue("")); | 448 result_.reset(Value::CreateStringValue("")); |
| 355 break; | 449 break; |
| 356 case UNKNOWN_ERROR: | 450 case UNKNOWN_ERROR: |
| (...skipping 10 matching lines...) Expand all Loading... |
| 367 break; | 461 break; |
| 368 case INVALID_ID: | 462 case INVALID_ID: |
| 369 result_.reset(Value::CreateStringValue("invalid_id")); | 463 result_.reset(Value::CreateStringValue("invalid_id")); |
| 370 break; | 464 break; |
| 371 case PERMISSION_DENIED: | 465 case PERMISSION_DENIED: |
| 372 result_.reset(Value::CreateStringValue("permission_denied")); | 466 result_.reset(Value::CreateStringValue("permission_denied")); |
| 373 break; | 467 break; |
| 374 case NO_GESTURE: | 468 case NO_GESTURE: |
| 375 result_.reset(Value::CreateStringValue("no_gesture")); | 469 result_.reset(Value::CreateStringValue("no_gesture")); |
| 376 break; | 470 break; |
| 471 case INVALID_ICON_URL: |
| 472 result_.reset(Value::CreateStringValue("invalid_icon_url")); |
| 473 break; |
| 377 default: | 474 default: |
| 378 CHECK(false); | 475 CHECK(false); |
| 379 } | 476 } |
| 380 } | 477 } |
| 381 | 478 |
| 382 // static | 479 // static |
| 383 void BeginInstallWithManifestFunction::SetIgnoreUserGestureForTests( | 480 void BeginInstallWithManifestFunction::SetIgnoreUserGestureForTests( |
| 384 bool ignore) { | 481 bool ignore) { |
| 385 ignore_user_gesture_for_tests = ignore; | 482 ignore_user_gesture_for_tests = ignore; |
| 386 } | 483 } |
| (...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 669 } | 766 } |
| 670 | 767 |
| 671 DCHECK(waiting_for_token_); | 768 DCHECK(waiting_for_token_); |
| 672 | 769 |
| 673 result_.reset(CreateLoginResult(profile_->GetOriginalProfile())); | 770 result_.reset(CreateLoginResult(profile_->GetOriginalProfile())); |
| 674 SendResponse(true); | 771 SendResponse(true); |
| 675 | 772 |
| 676 // Matches the AddRef in RunImpl(). | 773 // Matches the AddRef in RunImpl(). |
| 677 Release(); | 774 Release(); |
| 678 } | 775 } |
| OLD | NEW |