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

Side by Side Diff: chrome/common/extensions/extension_permission_set.cc

Issue 9317013: Add a centralized mechanism for whitelisting access to extension permissions. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: merge TerminalPrivate api changes Created 8 years, 10 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/common/extensions/extension_permission_set.h" 5 #include "chrome/common/extensions/extension_permission_set.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <string> 8 #include <string>
9 9
10 #include "base/command_line.h"
10 #include "base/memory/singleton.h" 11 #include "base/memory/singleton.h"
11 #include "base/values.h" 12 #include "base/values.h"
12 #include "base/string_number_conversions.h" 13 #include "base/string_number_conversions.h"
13 #include "base/utf_string_conversions.h" 14 #include "base/utf_string_conversions.h"
15 #include "chrome/common/chrome_switches.h"
14 #include "chrome/common/extensions/extension.h" 16 #include "chrome/common/extensions/extension.h"
15 #include "chrome/common/extensions/extension_constants.h" 17 #include "chrome/common/extensions/extension_constants.h"
16 #include "chrome/common/extensions/extension_l10n_util.h" 18 #include "chrome/common/extensions/extension_l10n_util.h"
17 #include "chrome/common/extensions/url_pattern.h" 19 #include "chrome/common/extensions/url_pattern.h"
18 #include "chrome/common/extensions/url_pattern_set.h" 20 #include "chrome/common/extensions/url_pattern_set.h"
19 #include "content/public/common/url_constants.h" 21 #include "content/public/common/url_constants.h"
20 #include "grit/generated_resources.h" 22 #include "grit/generated_resources.h"
21 #include "net/base/registry_controlled_domain.h" 23 #include "net/base/registry_controlled_domain.h"
22 #include "ui/base/l10n/l10n_util.h" 24 #include "ui/base/l10n/l10n_util.h"
23 25
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
59 const char* kNonPermissionFunctionNames[] = { 61 const char* kNonPermissionFunctionNames[] = {
60 "management.getPermissionWarningsByManifest", 62 "management.getPermissionWarningsByManifest",
61 "tabs.create", 63 "tabs.create",
62 "tabs.onRemoved", 64 "tabs.onRemoved",
63 "tabs.remove", 65 "tabs.remove",
64 "tabs.update", 66 "tabs.update",
65 }; 67 };
66 const size_t kNumNonPermissionFunctionNames = 68 const size_t kNumNonPermissionFunctionNames =
67 arraysize(kNonPermissionFunctionNames); 69 arraysize(kNonPermissionFunctionNames);
68 70
71 // TODO(jstritar): We should find out what these extensions are.
72
73 // ExtensionAPIPermission::kTerminalPrivate whitelist.
74 const char* kTerminalPrivateWhitelist[] = {
75 extension_misc::kHTermAppId
76 };
77
78 // ExtensionAPIPermission::kWebSocketProxyPrivate whitelist.
79 // ExtensionAPIPermission::kInputMethodPrivate whitelist.
80 const char* kChromeOSWhitelist[] = {
81 "haiffjcadagjlijoggckpgfnoeiflnem",
82 "gnedhmakppccajfpfiihfcdlnpgomkcf",
83 "fjcibdnjlbfnbfdjneajpipnlcppleek",
84 "okddffdblfhhnmhodogpojmfkjmhinfp",
tbarzic 2012/02/02 00:36:07 okddffdblfhhnmhodogpojmfkjmhinfp should also be ad
jstritar 2012/02/02 17:51:10 Done. Also added made sure that TerminalExtensionH
85 extension_misc::kHTermAppId
86 };
87
88 // ExtensionAPIPermission::kChromePrivate whitelist.
89 const char* kChromePrivateWhitelist[] = {
90 "haiffjcadagjlijoggckpgfnoeiflnem",
91 "gnedhmakppccajfpfiihfcdlnpgomkcf",
92 "fjcibdnjlbfnbfdjneajpipnlcppleek"
93 };
94
95 // ExtensionAPIPermission::kChromeAuthPrivate whitelist.
96 const char* kChromeAuthPrivateWhitelist[] = {
97 extension_misc::kCloudPrintAppId
98 };
99
100 // ExtensionAPIPermission::kWebstorePrivate whitelist.
101 const char* kWebstorePrivateWhitelist[] = {
102 extension_misc::kEnterpriseWebStoreAppId,
103 extension_misc::kWebStoreAppId
104 };
105
69 const char kOldUnlimitedStoragePermission[] = "unlimited_storage"; 106 const char kOldUnlimitedStoragePermission[] = "unlimited_storage";
70 const char kWindowsPermission[] = "windows"; 107 const char kWindowsPermission[] = "windows";
71 108
72 void AddPatternsAndRemovePaths(const URLPatternSet& set, URLPatternSet* out) { 109 void AddPatternsAndRemovePaths(const URLPatternSet& set, URLPatternSet* out) {
73 DCHECK(out); 110 DCHECK(out);
74 for (URLPatternSet::const_iterator i = set.begin(); i != set.end(); ++i) { 111 for (URLPatternSet::const_iterator i = set.begin(); i != set.end(); ++i) {
75 URLPattern p = *i; 112 URLPattern p = *i;
76 p.SetPath("/*"); 113 p.SetPath("/*");
77 out->AddPattern(p); 114 out->AddPattern(p);
78 } 115 }
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
191 kFlagCannotBeOptional, kTypeAll); 228 kFlagCannotBeOptional, kTypeAll);
192 info->RegisterPermission( 229 info->RegisterPermission(
193 kNotification, "notifications", 0, 230 kNotification, "notifications", 0,
194 ExtensionPermissionMessage::kNone, kFlagNone, kTypeAll); 231 ExtensionPermissionMessage::kNone, kFlagNone, kTypeAll);
195 info->RegisterPermission( 232 info->RegisterPermission(
196 kUnlimitedStorage, "unlimitedStorage", 0, 233 kUnlimitedStorage, "unlimitedStorage", 0,
197 ExtensionPermissionMessage::kNone, kFlagCannotBeOptional, kTypeAll); 234 ExtensionPermissionMessage::kNone, kFlagCannotBeOptional, kTypeAll);
198 235
199 // Register hosted app permissions that are also private. 236 // Register hosted app permissions that are also private.
200 info->RegisterPermission( 237 info->RegisterPermission(
201 kChromePrivate, "chromePrivate", 0, 238 kChromePrivate, "chromePrivate", 0, ExtensionPermissionMessage::kNone,
202 ExtensionPermissionMessage::kNone, kFlagCannotBeOptional, 239 kFlagCannotBeOptional | kFlagEnforceWhitelist,
203 kTypeAll - kTypePlatformApp); 240 kTypeAll - kTypePlatformApp);
204 info->RegisterPermission( 241 info->RegisterPermission(
205 kChromeAuthPrivate, "chromeAuthPrivate", 0, 242 kChromeAuthPrivate, "chromeAuthPrivate", 0,
206 ExtensionPermissionMessage::kNone, 243 ExtensionPermissionMessage::kNone,
207 kFlagComponentOnly | kFlagCannotBeOptional, kTypeAll - kTypePlatformApp); 244 kFlagComponentOnly | kFlagCannotBeOptional | kFlagEnforceWhitelist,
245 kTypeAll - kTypePlatformApp);
208 info->RegisterPermission( 246 info->RegisterPermission(
209 kWebstorePrivate, "webstorePrivate", 0, 247 kWebstorePrivate, "webstorePrivate", 0,
210 ExtensionPermissionMessage::kNone, 248 ExtensionPermissionMessage::kNone,
211 kFlagComponentOnly | kFlagCannotBeOptional, kTypeAll - kTypePlatformApp); 249 kFlagComponentOnly | kFlagCannotBeOptional | kFlagEnforceWhitelist,
250 kTypeAll - kTypePlatformApp);
212 251
213 // Register hosted and packaged app permissions. 252 // Register hosted and packaged app permissions.
214 info->RegisterPermission( 253 info->RegisterPermission(
215 kAppNotifications, "appNotifications", 0, 254 kAppNotifications, "appNotifications", 0,
216 ExtensionPermissionMessage::kNone, kFlagNone, 255 ExtensionPermissionMessage::kNone, kFlagNone,
217 kTypeHostedApp | kTypePackagedApp); 256 kTypeHostedApp | kTypePackagedApp);
218 257
219 // Register extension permissions. 258 // Register extension permissions.
220 info->RegisterPermission( 259 info->RegisterPermission(
221 kBookmark, "bookmarks", IDS_EXTENSION_PROMPT_WARNING_BOOKMARKS, 260 kBookmark, "bookmarks", IDS_EXTENSION_PROMPT_WARNING_BOOKMARKS,
(...skipping 17 matching lines...) Expand all
239 ExtensionPermissionMessage::kBrowsingHistory, 278 ExtensionPermissionMessage::kBrowsingHistory,
240 kFlagNone, kTypeDefault); 279 kFlagNone, kTypeDefault);
241 info->RegisterPermission( 280 info->RegisterPermission(
242 kIdle, "idle", 0, ExtensionPermissionMessage::kNone, 281 kIdle, "idle", 0, ExtensionPermissionMessage::kNone,
243 kFlagNone, kTypeDefault); 282 kFlagNone, kTypeDefault);
244 info->RegisterPermission( 283 info->RegisterPermission(
245 kInput, "input", 0, ExtensionPermissionMessage::kNone, 284 kInput, "input", 0, ExtensionPermissionMessage::kNone,
246 kFlagImpliesFullURLAccess, kTypeDefault); 285 kFlagImpliesFullURLAccess, kTypeDefault);
247 info->RegisterPermission( 286 info->RegisterPermission(
248 kInputMethodPrivate, "inputMethodPrivate", 0, 287 kInputMethodPrivate, "inputMethodPrivate", 0,
249 ExtensionPermissionMessage::kNone, kFlagCannotBeOptional, kTypeDefault); 288 ExtensionPermissionMessage::kNone,
289 kFlagCannotBeOptional | kFlagEnforceWhitelist, kTypeDefault);
250 info->RegisterPermission( 290 info->RegisterPermission(
251 kManagement, "management", IDS_EXTENSION_PROMPT_WARNING_MANAGEMENT, 291 kManagement, "management", IDS_EXTENSION_PROMPT_WARNING_MANAGEMENT,
252 ExtensionPermissionMessage::kManagement, kFlagNone, kTypeDefault); 292 ExtensionPermissionMessage::kManagement, kFlagNone, kTypeDefault);
253 info->RegisterPermission( 293 info->RegisterPermission(
254 kPageCapture, "pageCapture", 294 kPageCapture, "pageCapture",
255 IDS_EXTENSION_PROMPT_WARNING_ALL_PAGES_CONTENT, 295 IDS_EXTENSION_PROMPT_WARNING_ALL_PAGES_CONTENT,
256 ExtensionPermissionMessage::kAllPageContent, kFlagNone, kTypeDefault); 296 ExtensionPermissionMessage::kAllPageContent, kFlagNone, kTypeDefault);
257 info->RegisterPermission( 297 info->RegisterPermission(
258 kPrivacy, "privacy", IDS_EXTENSION_PROMPT_WARNING_PRIVACY, 298 kPrivacy, "privacy", IDS_EXTENSION_PROMPT_WARNING_PRIVACY,
259 ExtensionPermissionMessage::kPrivacy, kFlagNone, kTypeDefault); 299 ExtensionPermissionMessage::kPrivacy, kFlagNone, kTypeDefault);
260 info->RegisterPermission( 300 info->RegisterPermission(
261 kTab, "tabs", IDS_EXTENSION_PROMPT_WARNING_TABS, 301 kTab, "tabs", IDS_EXTENSION_PROMPT_WARNING_TABS,
262 ExtensionPermissionMessage::kTabs, kFlagNone, 302 ExtensionPermissionMessage::kTabs, kFlagNone,
263 kTypeDefault - kTypePlatformApp); 303 kTypeDefault - kTypePlatformApp);
264 info->RegisterPermission( 304 info->RegisterPermission(
265 kTerminalPrivate, "terminalPrivate", 0, 305 kTerminalPrivate, "terminalPrivate", 0, ExtensionPermissionMessage::kNone,
266 ExtensionPermissionMessage::kNone, kFlagCannotBeOptional, kTypeDefault); 306 kFlagCannotBeOptional | kFlagEnforceWhitelist, kTypeDefault);
267 info->RegisterPermission( 307 info->RegisterPermission(
268 kTts, "tts", 0, 308 kTts, "tts", 0,
269 ExtensionPermissionMessage::kNone, kFlagCannotBeOptional, kTypeDefault); 309 ExtensionPermissionMessage::kNone, kFlagCannotBeOptional, kTypeDefault);
270 info->RegisterPermission( 310 info->RegisterPermission(
271 kTtsEngine, "ttsEngine", IDS_EXTENSION_PROMPT_WARNING_TTS_ENGINE, 311 kTtsEngine, "ttsEngine", IDS_EXTENSION_PROMPT_WARNING_TTS_ENGINE,
272 ExtensionPermissionMessage::kTtsEngine, 312 ExtensionPermissionMessage::kTtsEngine,
273 kFlagCannotBeOptional, kTypeDefault); 313 kFlagCannotBeOptional, kTypeDefault);
274 info->RegisterPermission( 314 info->RegisterPermission(
275 kWebNavigation, "webNavigation", 315 kWebNavigation, "webNavigation",
276 IDS_EXTENSION_PROMPT_WARNING_TABS, ExtensionPermissionMessage::kTabs, 316 IDS_EXTENSION_PROMPT_WARNING_TABS, ExtensionPermissionMessage::kTabs,
277 kFlagNone, kTypeDefault - kTypePlatformApp); 317 kFlagNone, kTypeDefault - kTypePlatformApp);
278 info->RegisterPermission( 318 info->RegisterPermission(
279 kWebRequest, "webRequest", 0, ExtensionPermissionMessage::kNone, 319 kWebRequest, "webRequest", 0, ExtensionPermissionMessage::kNone,
280 kFlagNone, kTypeDefault - kTypePlatformApp); 320 kFlagNone, kTypeDefault - kTypePlatformApp);
281 info->RegisterPermission( 321 info->RegisterPermission(
282 kWebRequestBlocking, "webRequestBlocking", 0, 322 kWebRequestBlocking, "webRequestBlocking", 0,
283 ExtensionPermissionMessage::kNone, kFlagNone, 323 ExtensionPermissionMessage::kNone, kFlagNone,
284 kTypeDefault - kTypePlatformApp); 324 kTypeDefault - kTypePlatformApp);
285 info->RegisterPermission( 325 info->RegisterPermission(
286 kWebSocketProxyPrivate, "webSocketProxyPrivate", 0, 326 kWebSocketProxyPrivate, "webSocketProxyPrivate", 0,
287 ExtensionPermissionMessage::kNone, kFlagCannotBeOptional, 327 ExtensionPermissionMessage::kNone,
328 kFlagCannotBeOptional | kFlagEnforceWhitelist,
288 kTypeDefault - kTypePlatformApp); 329 kTypeDefault - kTypePlatformApp);
289 330
290 // Register private permissions. 331 // Register private permissions.
291 info->RegisterPermission( 332 info->RegisterPermission(
292 kChromeosInfoPrivate, "chromeosInfoPrivate", 0, 333 kChromeosInfoPrivate, "chromeosInfoPrivate", 0,
293 ExtensionPermissionMessage::kNone, 334 ExtensionPermissionMessage::kNone,
294 kFlagComponentOnly | kFlagCannotBeOptional, kTypeDefault); 335 kFlagComponentOnly | kFlagCannotBeOptional, kTypeDefault);
295 info->RegisterPermission( 336 info->RegisterPermission(
296 kFileBrowserPrivate, "fileBrowserPrivate", 0, 337 kFileBrowserPrivate, "fileBrowserPrivate", 0,
297 ExtensionPermissionMessage::kNone, 338 ExtensionPermissionMessage::kNone,
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
331 // Platform-app permissions. 372 // Platform-app permissions.
332 info->RegisterPermission( 373 info->RegisterPermission(
333 kSocket, "socket", 0, ExtensionPermissionMessage::kNone, 374 kSocket, "socket", 0, ExtensionPermissionMessage::kNone,
334 kFlagCannotBeOptional, kTypePlatformApp); 375 kFlagCannotBeOptional, kTypePlatformApp);
335 376
336 // Register aliases. 377 // Register aliases.
337 info->RegisterAlias("unlimitedStorage", kOldUnlimitedStoragePermission); 378 info->RegisterAlias("unlimitedStorage", kOldUnlimitedStoragePermission);
338 info->RegisterAlias("tabs", kWindowsPermission); 379 info->RegisterAlias("tabs", kWindowsPermission);
339 } 380 }
340 381
382 // static
383 void ExtensionAPIPermission::RegisterWhitelists(
384 ExtensionPermissionsInfo* info) {
385 info->RegisterWhitelist(kTerminalPrivate,
386 kTerminalPrivateWhitelist,
387 arraysize(kTerminalPrivateWhitelist));
388 info->RegisterWhitelist(kWebSocketProxyPrivate,
389 kChromeOSWhitelist,
390 arraysize(kChromeOSWhitelist));
391 info->RegisterWhitelist(kChromePrivate,
392 kChromePrivateWhitelist,
393 arraysize(kChromePrivateWhitelist));
394 info->RegisterWhitelist(kInputMethodPrivate,
395 kChromeOSWhitelist,
396 arraysize(kChromeOSWhitelist));
397 info->RegisterWhitelist(kChromeAuthPrivate,
398 kChromeAuthPrivateWhitelist,
399 arraysize(kChromeAuthPrivateWhitelist));
400 info->RegisterWhitelist(kWebstorePrivate,
401 kWebstorePrivateWhitelist,
402 arraysize(kWebstorePrivateWhitelist));
403 }
404
405 bool ExtensionAPIPermission::IsWhitelisted(
406 const std::string& extension_id) const {
407 DCHECK(should_enforce_whitelist());
408 return whitelist_.find(extension_id) != whitelist_.end();
409 }
410
411 void ExtensionAPIPermission::AddToWhitelist(const std::string& extension_id) {
412 DCHECK(should_enforce_whitelist());
413 whitelist_.insert(extension_id);
414 }
415
341 // 416 //
342 // ExtensionPermissionsInfo 417 // ExtensionPermissionsInfo
343 // 418 //
344 419
345 // static 420 // static
346 ExtensionPermissionsInfo* ExtensionPermissionsInfo::GetInstance() { 421 ExtensionPermissionsInfo* ExtensionPermissionsInfo::GetInstance() {
347 return Singleton<ExtensionPermissionsInfo>::get(); 422 return Singleton<ExtensionPermissionsInfo>::get();
348 } 423 }
349 424
350 ExtensionAPIPermission* ExtensionPermissionsInfo::GetByID( 425 ExtensionAPIPermission* ExtensionPermissionsInfo::GetByID(
(...skipping 28 matching lines...) Expand all
379 454
380 ExtensionPermissionsInfo::~ExtensionPermissionsInfo() { 455 ExtensionPermissionsInfo::~ExtensionPermissionsInfo() {
381 for (IDMap::iterator i = id_map_.begin(); i != id_map_.end(); ++i) 456 for (IDMap::iterator i = id_map_.begin(); i != id_map_.end(); ++i)
382 delete i->second; 457 delete i->second;
383 } 458 }
384 459
385 ExtensionPermissionsInfo::ExtensionPermissionsInfo() 460 ExtensionPermissionsInfo::ExtensionPermissionsInfo()
386 : hosted_app_permission_count_(0), 461 : hosted_app_permission_count_(0),
387 permission_count_(0) { 462 permission_count_(0) {
388 ExtensionAPIPermission::RegisterAllPermissions(this); 463 ExtensionAPIPermission::RegisterAllPermissions(this);
464 ExtensionAPIPermission::RegisterWhitelists(this);
389 } 465 }
390 466
391 void ExtensionPermissionsInfo::RegisterAlias( 467 void ExtensionPermissionsInfo::RegisterAlias(
392 const char* name, const char* alias) { 468 const char* name, const char* alias) {
393 DCHECK(name_map_.find(name) != name_map_.end()); 469 DCHECK(name_map_.find(name) != name_map_.end());
394 DCHECK(name_map_.find(alias) == name_map_.end()); 470 DCHECK(name_map_.find(alias) == name_map_.end());
395 name_map_[alias] = name_map_[name]; 471 name_map_[alias] = name_map_[name];
396 } 472 }
397 473
398 void ExtensionPermissionsInfo::RegisterPermission( 474 void ExtensionPermissionsInfo::RegisterPermission(
399 ExtensionAPIPermission::ID id, 475 ExtensionAPIPermission::ID id,
400 const char* name, 476 const char* name,
401 int l10n_message_id, 477 int l10n_message_id,
402 ExtensionPermissionMessage::ID message_id, 478 ExtensionPermissionMessage::ID message_id,
403 int flags, 479 int flags,
404 int type_restrictions) { 480 int type_restrictions) {
405 DCHECK(id_map_.find(id) == id_map_.end()); 481 DCHECK(id_map_.find(id) == id_map_.end());
406 DCHECK(name_map_.find(name) == name_map_.end()); 482 DCHECK(name_map_.find(name) == name_map_.end());
407 483
408 ExtensionAPIPermission* permission = new ExtensionAPIPermission( 484 ExtensionAPIPermission* permission = new ExtensionAPIPermission(
409 id, name, l10n_message_id, message_id, flags, type_restrictions); 485 id, name, l10n_message_id, message_id, flags, type_restrictions);
410 486
411 id_map_[id] = permission; 487 id_map_[id] = permission;
412 name_map_[name] = permission; 488 name_map_[name] = permission;
413 489
414 permission_count_++; 490 permission_count_++;
415 } 491 }
416 492
493 void ExtensionPermissionsInfo::RegisterWhitelist(
494 ExtensionAPIPermission::ID id,
495 const char* whitelist[],
496 int whitelist_length) {
497 ExtensionAPIPermission* permission = GetByID(id);
498 DCHECK(permission->should_enforce_whitelist());
499
500 for (int x = 0; x < whitelist_length; ++x)
501 permission->AddToWhitelist(whitelist[x]);
502
503 // Tests can add an extension ID to the whitelists via the command line.
504 CommandLine* command_line = CommandLine::ForCurrentProcess();
505 if (command_line->HasSwitch(switches::kWhitelistedExtensionID))
506 permission->AddToWhitelist(command_line->GetSwitchValueASCII(
507 switches::kWhitelistedExtensionID));
508 }
509
417 // 510 //
418 // ExtensionPermissionSet 511 // ExtensionPermissionSet
419 // 512 //
420 513
421 ExtensionPermissionSet::ExtensionPermissionSet() { 514 ExtensionPermissionSet::ExtensionPermissionSet() {
422 } 515 }
423 516
424 ExtensionPermissionSet::ExtensionPermissionSet( 517 ExtensionPermissionSet::ExtensionPermissionSet(
425 const Extension* extension, 518 const Extension* extension,
426 const ExtensionAPIPermissionSet& apis, 519 const ExtensionAPIPermissionSet& apis,
(...skipping 440 matching lines...) Expand 10 before | Expand all | Expand 10 after
867 std::set<std::string> new_hosts_set(GetDistinctHosts(new_list, false, false)); 960 std::set<std::string> new_hosts_set(GetDistinctHosts(new_list, false, false));
868 std::set<std::string> old_hosts_set(GetDistinctHosts(old_list, false, false)); 961 std::set<std::string> old_hosts_set(GetDistinctHosts(old_list, false, false));
869 std::set<std::string> new_hosts_only; 962 std::set<std::string> new_hosts_only;
870 963
871 std::set_difference(new_hosts_set.begin(), new_hosts_set.end(), 964 std::set_difference(new_hosts_set.begin(), new_hosts_set.end(),
872 old_hosts_set.begin(), old_hosts_set.end(), 965 old_hosts_set.begin(), old_hosts_set.end(),
873 std::inserter(new_hosts_only, new_hosts_only.begin())); 966 std::inserter(new_hosts_only, new_hosts_only.begin()));
874 967
875 return !new_hosts_only.empty(); 968 return !new_hosts_only.empty();
876 } 969 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698