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

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: rework Created 7 years, 7 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 &&
137 profile->IsSameProfile(install.first)) {
138 return (installs_.begin() + i);
139 }
140 }
141 return installs_.end();
142 }
asargent_no_longer_on_chrome 2013/05/21 19:47:24 Can you get away with not having this class at all
calamity 2013/05/24 00:24:28 We can't use set because there's no ordering, C++1
asargent_no_longer_on_chrome 2013/05/28 21:35:33 Ok, good point - sounds like it wouldn't actually
asargent_no_longer_on_chrome 2013/05/28 23:03:52 Actually, here's one other possibility for you - y
143
89 static base::LazyInstance<PendingApprovals> g_pending_approvals = 144 static base::LazyInstance<PendingApprovals> g_pending_approvals =
90 LAZY_INSTANCE_INITIALIZER; 145 LAZY_INSTANCE_INITIALIZER;
146 static base::LazyInstance<PendingInstalls> g_pending_installs =
147 LAZY_INSTANCE_INITIALIZER;
91 148
92 const char kAppInstallBubbleKey[] = "appInstallBubble"; 149 const char kAppInstallBubbleKey[] = "appInstallBubble";
93 const char kEnableLauncherKey[] = "enableLauncher"; 150 const char kEnableLauncherKey[] = "enableLauncher";
94 const char kIconDataKey[] = "iconData"; 151 const char kIconDataKey[] = "iconData";
95 const char kIconUrlKey[] = "iconUrl"; 152 const char kIconUrlKey[] = "iconUrl";
96 const char kIdKey[] = "id"; 153 const char kIdKey[] = "id";
97 const char kLocalizedNameKey[] = "localizedName"; 154 const char kLocalizedNameKey[] = "localizedName";
98 const char kLoginKey[] = "login"; 155 const char kLoginKey[] = "login";
99 const char kManifestKey[] = "manifest"; 156 const char kManifestKey[] = "manifest";
100 157
158 const char kAlreadyInstalledError[] = "This item is already installed";
101 const char kCannotSpecifyIconDataAndUrlError[] = 159 const char kCannotSpecifyIconDataAndUrlError[] =
102 "You cannot specify both icon data and an icon url"; 160 "You cannot specify both icon data and an icon url";
103 const char kInvalidIconUrlError[] = "Invalid icon url"; 161 const char kInvalidIconUrlError[] = "Invalid icon url";
104 const char kInvalidIdError[] = "Invalid id"; 162 const char kInvalidIdError[] = "Invalid id";
105 const char kInvalidManifestError[] = "Invalid manifest"; 163 const char kInvalidManifestError[] = "Invalid manifest";
106 const char kNoPreviousBeginInstallWithManifestError[] = 164 const char kNoPreviousBeginInstallWithManifestError[] =
107 "* does not match a previous call to beginInstallWithManifest3"; 165 "* does not match a previous call to beginInstallWithManifest3";
108 const char kUserCancelledError[] = "User cancelled install"; 166 const char kUserCancelledError[] = "User cancelled install";
109 167
110 // Helper to create a dictionary with login properties set from the appropriate 168 // Helper to create a dictionary with login properties set from the appropriate
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
216 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &details)); 274 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &details));
217 CHECK(details); 275 CHECK(details);
218 276
219 EXTENSION_FUNCTION_VALIDATE(details->GetString(kIdKey, &id_)); 277 EXTENSION_FUNCTION_VALIDATE(details->GetString(kIdKey, &id_));
220 if (!extensions::Extension::IdIsValid(id_)) { 278 if (!extensions::Extension::IdIsValid(id_)) {
221 SetResultCode(INVALID_ID); 279 SetResultCode(INVALID_ID);
222 error_ = kInvalidIdError; 280 error_ = kInvalidIdError;
223 return false; 281 return false;
224 } 282 }
225 283
284 ExtensionService* service =
285 extensions::ExtensionSystem::Get(profile_)->extension_service();
286 if (service->GetInstalledExtension(id_) ||
287 !g_pending_installs.Get().InsertInstall(profile_, id_)) {
288 SetResultCode(ALREADY_INSTALLED);
289 error_ = kAlreadyInstalledError;
290 return false;
291 }
292
226 EXTENSION_FUNCTION_VALIDATE(details->GetString(kManifestKey, &manifest_)); 293 EXTENSION_FUNCTION_VALIDATE(details->GetString(kManifestKey, &manifest_));
227 294
228 if (details->HasKey(kIconDataKey) && details->HasKey(kIconUrlKey)) { 295 if (details->HasKey(kIconDataKey) && details->HasKey(kIconUrlKey)) {
229 SetResultCode(ICON_ERROR); 296 SetResultCode(ICON_ERROR);
230 error_ = kCannotSpecifyIconDataAndUrlError; 297 error_ = kCannotSpecifyIconDataAndUrlError;
231 return false; 298 return false;
232 } 299 }
233 300
234 if (details->HasKey(kIconDataKey)) 301 if (details->HasKey(kIconDataKey))
235 EXTENSION_FUNCTION_VALIDATE(details->GetString(kIconDataKey, &icon_data_)); 302 EXTENSION_FUNCTION_VALIDATE(details->GetString(kIconDataKey, &icon_data_));
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
300 break; 367 break;
301 case PERMISSION_DENIED: 368 case PERMISSION_DENIED:
302 SetResult(Value::CreateStringValue("permission_denied")); 369 SetResult(Value::CreateStringValue("permission_denied"));
303 break; 370 break;
304 case INVALID_ICON_URL: 371 case INVALID_ICON_URL:
305 SetResult(Value::CreateStringValue("invalid_icon_url")); 372 SetResult(Value::CreateStringValue("invalid_icon_url"));
306 break; 373 break;
307 case SIGNIN_FAILED: 374 case SIGNIN_FAILED:
308 SetResult(Value::CreateStringValue("signin_failed")); 375 SetResult(Value::CreateStringValue("signin_failed"));
309 break; 376 break;
377 case ALREADY_INSTALLED:
378 SetResult(Value::CreateStringValue("already_installed"));
379 break;
310 default: 380 default:
311 CHECK(false); 381 CHECK(false);
312 } 382 }
313 } 383 }
314 384
315 void BeginInstallWithManifestFunction::OnWebstoreParseSuccess( 385 void BeginInstallWithManifestFunction::OnWebstoreParseSuccess(
316 const std::string& id, 386 const std::string& id,
317 const SkBitmap& icon, 387 const SkBitmap& icon,
318 DictionaryValue* parsed_manifest) { 388 DictionaryValue* parsed_manifest) {
319 CHECK_EQ(id_, id); 389 CHECK_EQ(id_, id);
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
525 &(dispatcher()->delegate()->GetAssociatedWebContents()->GetController()), 595 &(dispatcher()->delegate()->GetAssociatedWebContents()->GetController()),
526 id, approval_.Pass(), WebstoreInstaller::FLAG_NONE); 596 id, approval_.Pass(), WebstoreInstaller::FLAG_NONE);
527 installer->Start(); 597 installer->Start();
528 } 598 }
529 599
530 void CompleteInstallFunction::OnExtensionInstallSuccess( 600 void CompleteInstallFunction::OnExtensionInstallSuccess(
531 const std::string& id) { 601 const std::string& id) {
532 if (test_webstore_installer_delegate) 602 if (test_webstore_installer_delegate)
533 test_webstore_installer_delegate->OnExtensionInstallSuccess(id); 603 test_webstore_installer_delegate->OnExtensionInstallSuccess(id);
534 604
605 g_pending_installs.Get().EraseInstall(profile_, id);
606
535 LOG(INFO) << "Install success, sending response"; 607 LOG(INFO) << "Install success, sending response";
536 SendResponse(true); 608 SendResponse(true);
537 609
538 // Matches the AddRef in RunImpl(). 610 // Matches the AddRef in RunImpl().
539 Release(); 611 Release();
540 } 612 }
541 613
542 void CompleteInstallFunction::OnExtensionInstallFailure( 614 void CompleteInstallFunction::OnExtensionInstallFailure(
543 const std::string& id, 615 const std::string& id,
544 const std::string& error, 616 const std::string& error,
545 WebstoreInstaller::FailureReason reason) { 617 WebstoreInstaller::FailureReason reason) {
546 extensions::InstallTracker* tracker = 618 extensions::InstallTracker* tracker =
547 extensions::InstallTrackerFactory::GetForProfile(profile()); 619 extensions::InstallTrackerFactory::GetForProfile(profile());
548 tracker->OnInstallFailure(id); 620 tracker->OnInstallFailure(id);
549 if (test_webstore_installer_delegate) { 621 if (test_webstore_installer_delegate) {
550 test_webstore_installer_delegate->OnExtensionInstallFailure( 622 test_webstore_installer_delegate->OnExtensionInstallFailure(
551 id, error, reason); 623 id, error, reason);
552 } 624 }
553 625
626 g_pending_installs.Get().EraseInstall(profile_, id);
627
554 error_ = error; 628 error_ = error;
555 LOG(INFO) << "Install failed, sending response"; 629 LOG(INFO) << "Install failed, sending response";
556 SendResponse(false); 630 SendResponse(false);
557 631
558 // Matches the AddRef in RunImpl(). 632 // Matches the AddRef in RunImpl().
559 Release(); 633 Release();
560 } 634 }
561 635
562 void CompleteInstallFunction::OnExtensionDownloadProgress( 636 void CompleteInstallFunction::OnExtensionDownloadProgress(
563 const std::string& id, 637 const std::string& id,
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
640 &GetIsLauncherEnabledFunction::OnIsLauncherCheckCompleted, this)); 714 &GetIsLauncherEnabledFunction::OnIsLauncherCheckCompleted, this));
641 return true; 715 return true;
642 } 716 }
643 717
644 void GetIsLauncherEnabledFunction::OnIsLauncherCheckCompleted(bool is_enabled) { 718 void GetIsLauncherEnabledFunction::OnIsLauncherCheckCompleted(bool is_enabled) {
645 SetResult(Value::CreateBooleanValue(is_enabled)); 719 SetResult(Value::CreateBooleanValue(is_enabled));
646 SendResponse(true); 720 SendResponse(true);
647 } 721 }
648 722
649 } // namespace extensions 723 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698