Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(478)

Side by Side Diff: chrome/browser/extensions/api/webstore_private/webstore_private_api.cc

Issue 15292011: Prevent duplicate webstore install requests being serviced. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix tests Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 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/api/webstore_private/webstore_private_api.h" 5 #include "chrome/browser/extensions/api/webstore_private/webstore_private_api.h"
6 6
7 #include "apps/app_launcher.h" 7 #include "apps/app_launcher.h"
8 #include "base/bind_helpers.h" 8 #include "base/bind_helpers.h"
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/lazy_instance.h" 10 #include "base/lazy_instance.h"
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
45 #include "grit/generated_resources.h" 45 #include "grit/generated_resources.h"
46 #include "ui/base/l10n/l10n_util.h" 46 #include "ui/base/l10n/l10n_util.h"
47 47
48 using content::GpuDataManager; 48 using content::GpuDataManager;
49 49
50 namespace extensions { 50 namespace extensions {
51 51
52 namespace { 52 namespace {
53 53
54 // Holds the Approvals between the time we prompt and start the installs. 54 // Holds the Approvals between the time we prompt and start the installs.
55 struct PendingApprovals { 55 class PendingApprovals {
56 typedef ScopedVector<WebstoreInstaller::Approval> ApprovalList; 56 public:
57
58 PendingApprovals(); 57 PendingApprovals();
59 ~PendingApprovals(); 58 ~PendingApprovals();
60 59
61 void PushApproval(scoped_ptr<WebstoreInstaller::Approval> approval); 60 void PushApproval(scoped_ptr<WebstoreInstaller::Approval> approval);
62 scoped_ptr<WebstoreInstaller::Approval> PopApproval( 61 scoped_ptr<WebstoreInstaller::Approval> PopApproval(
63 Profile* profile, const std::string& id); 62 Profile* profile, const std::string& id);
63 private:
64 typedef ScopedVector<WebstoreInstaller::Approval> ApprovalList;
64 65
65 ApprovalList approvals; 66 ApprovalList approvals_;
67
68 DISALLOW_COPY_AND_ASSIGN(PendingApprovals);
66 }; 69 };
67 70
68 PendingApprovals::PendingApprovals() {} 71 PendingApprovals::PendingApprovals() {}
69 PendingApprovals::~PendingApprovals() {} 72 PendingApprovals::~PendingApprovals() {}
70 73
71 void PendingApprovals::PushApproval( 74 void PendingApprovals::PushApproval(
72 scoped_ptr<WebstoreInstaller::Approval> approval) { 75 scoped_ptr<WebstoreInstaller::Approval> approval) {
73 approvals.push_back(approval.release()); 76 approvals_.push_back(approval.release());
74 } 77 }
75 78
76 scoped_ptr<WebstoreInstaller::Approval> PendingApprovals::PopApproval( 79 scoped_ptr<WebstoreInstaller::Approval> PendingApprovals::PopApproval(
77 Profile* profile, const std::string& id) { 80 Profile* profile, const std::string& id) {
78 for (size_t i = 0; i < approvals.size(); ++i) { 81 for (size_t i = 0; i < approvals_.size(); ++i) {
79 WebstoreInstaller::Approval* approval = approvals[i]; 82 WebstoreInstaller::Approval* approval = approvals_[i];
80 if (approval->extension_id == id && 83 if (approval->extension_id == id &&
81 profile->IsSameProfile(approval->profile)) { 84 profile->IsSameProfile(approval->profile)) {
82 approvals.weak_erase(approvals.begin() + i); 85 approvals_.weak_erase(approvals_.begin() + i);
83 return scoped_ptr<WebstoreInstaller::Approval>(approval); 86 return scoped_ptr<WebstoreInstaller::Approval>(approval);
84 } 87 }
85 } 88 }
86 return scoped_ptr<WebstoreInstaller::Approval>(NULL); 89 return scoped_ptr<WebstoreInstaller::Approval>(NULL);
87 } 90 }
88 91
92 // Uniquely holds the profile and extension id of an install between the time we
93 // prompt and complete the installs.
94 class PendingInstalls {
95 public:
96 PendingInstalls();
97 ~PendingInstalls();
98
99 bool InsertInstall(Profile* profile, const std::string& id);
100 void EraseInstall(Profile* profile, const std::string& id);
101 private:
102 typedef std::pair<Profile*, std::string> ProfileAndExtensionId;
103 typedef std::vector<ProfileAndExtensionId> InstallList;
104
105 InstallList::iterator FindInstall(Profile* profile, const std::string& id);
106
107 InstallList installs_;
108
109 DISALLOW_COPY_AND_ASSIGN(PendingInstalls);
110 };
111
112 PendingInstalls::PendingInstalls() {}
113 PendingInstalls::~PendingInstalls() {}
114
115 // Returns true and inserts the profile/id pair if it is not present. Otherwise
116 // returns false.
117 bool PendingInstalls::InsertInstall(Profile* profile, const std::string& id) {
118 if (FindInstall(profile, id) != installs_.end())
119 return false;
120 installs_.push_back(make_pair(profile, id));
121 return true;
122 }
123
124 // Removes the given profile/id pair.
125 void PendingInstalls::EraseInstall(Profile* profile, const std::string& id) {
126 InstallList::iterator it = FindInstall(profile, id);
127 if (it != installs_.end())
128 installs_.erase(it);
129 }
130
131 PendingInstalls::InstallList::iterator PendingInstalls::FindInstall(
132 Profile* profile,
133 const std::string& id) {
134 for (size_t i = 0; i < installs_.size(); ++i) {
135 ProfileAndExtensionId install = installs_[i];
136 if (install.second == id && profile->IsSameProfile(install.first))
137 return (installs_.begin() + i);
138 }
139 return installs_.end();
140 }
141
89 static base::LazyInstance<PendingApprovals> g_pending_approvals = 142 static base::LazyInstance<PendingApprovals> g_pending_approvals =
90 LAZY_INSTANCE_INITIALIZER; 143 LAZY_INSTANCE_INITIALIZER;
144 static base::LazyInstance<PendingInstalls> g_pending_installs =
145 LAZY_INSTANCE_INITIALIZER;
91 146
92 const char kAppInstallBubbleKey[] = "appInstallBubble"; 147 const char kAppInstallBubbleKey[] = "appInstallBubble";
93 const char kEnableLauncherKey[] = "enableLauncher"; 148 const char kEnableLauncherKey[] = "enableLauncher";
94 const char kIconDataKey[] = "iconData"; 149 const char kIconDataKey[] = "iconData";
95 const char kIconUrlKey[] = "iconUrl"; 150 const char kIconUrlKey[] = "iconUrl";
96 const char kIdKey[] = "id"; 151 const char kIdKey[] = "id";
97 const char kLocalizedNameKey[] = "localizedName"; 152 const char kLocalizedNameKey[] = "localizedName";
98 const char kLoginKey[] = "login"; 153 const char kLoginKey[] = "login";
99 const char kManifestKey[] = "manifest"; 154 const char kManifestKey[] = "manifest";
100 155
101 // A preference set by the web store to indicate login information for 156 // A preference set by the web store to indicate login information for
102 // purchased apps. 157 // purchased apps.
103 const char kWebstoreLogin[] = "extensions.webstore_login"; 158 const char kWebstoreLogin[] = "extensions.webstore_login";
104 159 const char kAlreadyInstalledError[] = "This item is already installed";
105 const char kCannotSpecifyIconDataAndUrlError[] = 160 const char kCannotSpecifyIconDataAndUrlError[] =
106 "You cannot specify both icon data and an icon url"; 161 "You cannot specify both icon data and an icon url";
107 const char kInvalidIconUrlError[] = "Invalid icon url"; 162 const char kInvalidIconUrlError[] = "Invalid icon url";
108 const char kInvalidIdError[] = "Invalid id"; 163 const char kInvalidIdError[] = "Invalid id";
109 const char kInvalidManifestError[] = "Invalid manifest"; 164 const char kInvalidManifestError[] = "Invalid manifest";
110 const char kNoPreviousBeginInstallWithManifestError[] = 165 const char kNoPreviousBeginInstallWithManifestError[] =
111 "* does not match a previous call to beginInstallWithManifest3"; 166 "* does not match a previous call to beginInstallWithManifest3";
112 const char kUserCancelledError[] = "User cancelled install"; 167 const char kUserCancelledError[] = "User cancelled install";
113 168
114 // Helper to create a dictionary with login properties set from the appropriate 169 // Helper to create a dictionary with login properties set from the appropriate
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
270 &localized_name_)); 325 &localized_name_));
271 326
272 if (details->HasKey(kAppInstallBubbleKey)) 327 if (details->HasKey(kAppInstallBubbleKey))
273 EXTENSION_FUNCTION_VALIDATE(details->GetBoolean( 328 EXTENSION_FUNCTION_VALIDATE(details->GetBoolean(
274 kAppInstallBubbleKey, &use_app_installed_bubble_)); 329 kAppInstallBubbleKey, &use_app_installed_bubble_));
275 330
276 if (details->HasKey(kEnableLauncherKey)) 331 if (details->HasKey(kEnableLauncherKey))
277 EXTENSION_FUNCTION_VALIDATE(details->GetBoolean( 332 EXTENSION_FUNCTION_VALIDATE(details->GetBoolean(
278 kEnableLauncherKey, &enable_launcher_)); 333 kEnableLauncherKey, &enable_launcher_));
279 334
335 ExtensionService* service =
336 extensions::ExtensionSystem::Get(profile_)->extension_service();
337 if (service->GetInstalledExtension(id_) ||
338 !g_pending_installs.Get().InsertInstall(profile_, id_)) {
339 SetResultCode(ALREADY_INSTALLED);
340 error_ = kAlreadyInstalledError;
341 return false;
342 }
343
280 net::URLRequestContextGetter* context_getter = NULL; 344 net::URLRequestContextGetter* context_getter = NULL;
281 if (!icon_url.is_empty()) 345 if (!icon_url.is_empty())
282 context_getter = profile()->GetRequestContext(); 346 context_getter = profile()->GetRequestContext();
283 347
284 scoped_refptr<WebstoreInstallHelper> helper = new WebstoreInstallHelper( 348 scoped_refptr<WebstoreInstallHelper> helper = new WebstoreInstallHelper(
285 this, id_, manifest_, icon_data_, icon_url, context_getter); 349 this, id_, manifest_, icon_data_, icon_url, context_getter);
286 350
287 // The helper will call us back via OnWebstoreParseSuccess or 351 // The helper will call us back via OnWebstoreParseSuccess or
288 // OnWebstoreParseFailure. 352 // OnWebstoreParseFailure.
289 helper->Start(); 353 helper->Start();
(...skipping 29 matching lines...) Expand all
319 break; 383 break;
320 case PERMISSION_DENIED: 384 case PERMISSION_DENIED:
321 SetResult(Value::CreateStringValue("permission_denied")); 385 SetResult(Value::CreateStringValue("permission_denied"));
322 break; 386 break;
323 case INVALID_ICON_URL: 387 case INVALID_ICON_URL:
324 SetResult(Value::CreateStringValue("invalid_icon_url")); 388 SetResult(Value::CreateStringValue("invalid_icon_url"));
325 break; 389 break;
326 case SIGNIN_FAILED: 390 case SIGNIN_FAILED:
327 SetResult(Value::CreateStringValue("signin_failed")); 391 SetResult(Value::CreateStringValue("signin_failed"));
328 break; 392 break;
393 case ALREADY_INSTALLED:
394 SetResult(Value::CreateStringValue("already_installed"));
395 break;
329 default: 396 default:
330 CHECK(false); 397 CHECK(false);
331 } 398 }
332 } 399 }
333 400
334 void BeginInstallWithManifestFunction::OnWebstoreParseSuccess( 401 void BeginInstallWithManifestFunction::OnWebstoreParseSuccess(
335 const std::string& id, 402 const std::string& id,
336 const SkBitmap& icon, 403 const SkBitmap& icon,
337 DictionaryValue* parsed_manifest) { 404 DictionaryValue* parsed_manifest) {
338 CHECK_EQ(id_, id); 405 CHECK_EQ(id_, id);
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
381 case WebstoreInstallHelper::Delegate::ICON_ERROR: 448 case WebstoreInstallHelper::Delegate::ICON_ERROR:
382 SetResultCode(ICON_ERROR); 449 SetResultCode(ICON_ERROR);
383 break; 450 break;
384 case WebstoreInstallHelper::Delegate::MANIFEST_ERROR: 451 case WebstoreInstallHelper::Delegate::MANIFEST_ERROR:
385 SetResultCode(MANIFEST_ERROR); 452 SetResultCode(MANIFEST_ERROR);
386 break; 453 break;
387 default: 454 default:
388 CHECK(false); 455 CHECK(false);
389 } 456 }
390 error_ = error_message; 457 error_ = error_message;
458 g_pending_installs.Get().EraseInstall(profile_, id);
391 SendResponse(false); 459 SendResponse(false);
392 460
393 // Matches the AddRef in RunImpl(). 461 // Matches the AddRef in RunImpl().
394 Release(); 462 Release();
395 } 463 }
396 464
397 void BeginInstallWithManifestFunction::GaiaCredentialsValid() {} 465 void BeginInstallWithManifestFunction::GaiaCredentialsValid() {}
398 466
399 void BeginInstallWithManifestFunction::SigninFailed( 467 void BeginInstallWithManifestFunction::SigninFailed(
400 const GoogleServiceAuthError& error) { 468 const GoogleServiceAuthError& error) {
401 signin_tracker_.reset(); 469 signin_tracker_.reset();
402 470
403 SetResultCode(SIGNIN_FAILED); 471 SetResultCode(SIGNIN_FAILED);
404 error_ = error.ToString(); 472 error_ = error.ToString();
473 g_pending_installs.Get().EraseInstall(profile_, id_);
405 SendResponse(false); 474 SendResponse(false);
406 475
407 // Matches the AddRef in RunImpl(). 476 // Matches the AddRef in RunImpl().
408 Release(); 477 Release();
409 } 478 }
410 479
411 void BeginInstallWithManifestFunction::SigninSuccess() { 480 void BeginInstallWithManifestFunction::SigninSuccess() {
412 signin_tracker_.reset(); 481 signin_tracker_.reset();
413 482
414 SigninCompletedOrNotNeeded(); 483 SigninCompletedOrNotNeeded();
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
448 ExtensionService::RecordPermissionMessagesHistogram( 517 ExtensionService::RecordPermissionMessagesHistogram(
449 dummy_extension_, "Extensions.Permissions_WebStoreInstall"); 518 dummy_extension_, "Extensions.Permissions_WebStoreInstall");
450 519
451 // Matches the AddRef in RunImpl(). 520 // Matches the AddRef in RunImpl().
452 Release(); 521 Release();
453 } 522 }
454 523
455 void BeginInstallWithManifestFunction::InstallUIAbort(bool user_initiated) { 524 void BeginInstallWithManifestFunction::InstallUIAbort(bool user_initiated) {
456 error_ = kUserCancelledError; 525 error_ = kUserCancelledError;
457 SetResultCode(USER_CANCELLED); 526 SetResultCode(USER_CANCELLED);
527 g_pending_installs.Get().EraseInstall(profile_, id_);
458 SendResponse(false); 528 SendResponse(false);
459 529
460 // The web store install histograms are a subset of the install histograms. 530 // The web store install histograms are a subset of the install histograms.
461 // We need to record both histograms here since CrxInstaller::InstallUIAbort 531 // We need to record both histograms here since CrxInstaller::InstallUIAbort
462 // is never called for web store install cancellations. 532 // is never called for web store install cancellations.
463 std::string histogram_name = user_initiated ? 533 std::string histogram_name = user_initiated ?
464 "Extensions.Permissions_WebStoreInstallCancel" : 534 "Extensions.Permissions_WebStoreInstallCancel" :
465 "Extensions.Permissions_WebStoreInstallAbort"; 535 "Extensions.Permissions_WebStoreInstallAbort";
466 ExtensionService::RecordPermissionMessagesHistogram( 536 ExtensionService::RecordPermissionMessagesHistogram(
467 dummy_extension_, histogram_name.c_str()); 537 dummy_extension_, histogram_name.c_str());
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
545 id, approval_.Pass(), WebstoreInstaller::FLAG_NONE); 615 id, approval_.Pass(), WebstoreInstaller::FLAG_NONE);
546 installer->Start(); 616 installer->Start();
547 } 617 }
548 618
549 void CompleteInstallFunction::OnExtensionInstallSuccess( 619 void CompleteInstallFunction::OnExtensionInstallSuccess(
550 const std::string& id) { 620 const std::string& id) {
551 if (test_webstore_installer_delegate) 621 if (test_webstore_installer_delegate)
552 test_webstore_installer_delegate->OnExtensionInstallSuccess(id); 622 test_webstore_installer_delegate->OnExtensionInstallSuccess(id);
553 623
554 LOG(INFO) << "Install success, sending response"; 624 LOG(INFO) << "Install success, sending response";
625 g_pending_installs.Get().EraseInstall(profile_, id);
555 SendResponse(true); 626 SendResponse(true);
556 627
557 // Matches the AddRef in RunImpl(). 628 // Matches the AddRef in RunImpl().
558 Release(); 629 Release();
559 } 630 }
560 631
561 void CompleteInstallFunction::OnExtensionInstallFailure( 632 void CompleteInstallFunction::OnExtensionInstallFailure(
562 const std::string& id, 633 const std::string& id,
563 const std::string& error, 634 const std::string& error,
564 WebstoreInstaller::FailureReason reason) { 635 WebstoreInstaller::FailureReason reason) {
565 extensions::InstallTracker* tracker = 636 extensions::InstallTracker* tracker =
566 extensions::InstallTrackerFactory::GetForProfile(profile()); 637 extensions::InstallTrackerFactory::GetForProfile(profile());
567 tracker->OnInstallFailure(id); 638 tracker->OnInstallFailure(id);
568 if (test_webstore_installer_delegate) { 639 if (test_webstore_installer_delegate) {
569 test_webstore_installer_delegate->OnExtensionInstallFailure( 640 test_webstore_installer_delegate->OnExtensionInstallFailure(
570 id, error, reason); 641 id, error, reason);
571 } 642 }
572 643
573 error_ = error; 644 error_ = error;
574 LOG(INFO) << "Install failed, sending response"; 645 LOG(INFO) << "Install failed, sending response";
646 g_pending_installs.Get().EraseInstall(profile_, id);
575 SendResponse(false); 647 SendResponse(false);
576 648
577 // Matches the AddRef in RunImpl(). 649 // Matches the AddRef in RunImpl().
578 Release(); 650 Release();
579 } 651 }
580 652
581 void CompleteInstallFunction::OnExtensionDownloadProgress( 653 void CompleteInstallFunction::OnExtensionDownloadProgress(
582 const std::string& id, 654 const std::string& id,
583 content::DownloadItem* item) { 655 content::DownloadItem* item) {
584 extensions::InstallTracker* tracker = 656 extensions::InstallTracker* tracker =
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
648 &GetIsLauncherEnabledFunction::OnIsLauncherCheckCompleted, this)); 720 &GetIsLauncherEnabledFunction::OnIsLauncherCheckCompleted, this));
649 return true; 721 return true;
650 } 722 }
651 723
652 void GetIsLauncherEnabledFunction::OnIsLauncherCheckCompleted(bool is_enabled) { 724 void GetIsLauncherEnabledFunction::OnIsLauncherCheckCompleted(bool is_enabled) {
653 SetResult(Value::CreateBooleanValue(is_enabled)); 725 SetResult(Value::CreateBooleanValue(is_enabled));
654 SendResponse(true); 726 SendResponse(true);
655 } 727 }
656 728
657 } // namespace extensions 729 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698