// Copyright 2013 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "extensions/common/extension_set.h" #include "base/containers/contains.h" #include "base/containers/map_util.h" #include "extensions/common/constants.h" #include "extensions/common/url_pattern_set.h" #include "url/gurl.h" #include "url/origin.h" namespace extensions { // static // TODO(solomonkinard): Take GUID-based dynamic URLs in account. Also, // disambiguate ExtensionHost. ExtensionId ExtensionSet::GetExtensionIdByURL(const GURL& url) { if (url.SchemeIs(kExtensionScheme)) return url.host(); // Trying url::Origin is important to properly handle extension schemes inside // blob: and filesystem: URLs, which won't match the extension scheme check // above. url::Origin origin = url::Origin::Create(url); if (origin.scheme() == kExtensionScheme) return origin.host(); return ExtensionId(); } ExtensionSet::const_iterator::const_iterator() = default; ExtensionSet::const_iterator::const_iterator(const const_iterator& other) : it_(other.it_) { } ExtensionSet::const_iterator::const_iterator(ExtensionMap::const_iterator it) : it_(it) { } ExtensionSet::const_iterator::~const_iterator() = default; ExtensionSet::ExtensionSet() = default; ExtensionSet::~ExtensionSet() = default; ExtensionSet::ExtensionSet(ExtensionSet&&) = default; ExtensionSet& ExtensionSet::operator=(ExtensionSet&&) noexcept = default; bool ExtensionSet::Contains(const ExtensionId& extension_id) const { return base::Contains(extensions_, extension_id); } bool ExtensionSet::Insert(const scoped_refptr& extension) { auto iter = extensions_.find(extension->id()); if (iter != extensions_.end()) { iter->second = extension; return false; // Had a previous entry. } extensions_.emplace(extension->id(), extension); return true; // New entry added. } bool ExtensionSet::InsertAll(const ExtensionSet& extensions) { size_t before = size(); for (const auto& extension : extensions) { Insert(extension); } return size() != before; } bool ExtensionSet::Remove(const ExtensionId& id) { return extensions_.erase(id) > 0; } void ExtensionSet::Clear() { extensions_.clear(); } ExtensionId ExtensionSet::GetExtensionOrAppIDByURL(const GURL& url) const { ExtensionId extension_id = GetExtensionIdByURL(url); if (!extension_id.empty()) return extension_id; // GetHostedAppByURL already supports filesystem: URLs (via MatchesURL). // TODO(crbug.com/41394231): Add support for blob: URLs in MatchesURL. const Extension* extension = GetHostedAppByURL(url); if (!extension) return ExtensionId(); return extension->id(); } const Extension* ExtensionSet::GetExtensionOrAppByURL(const GURL& url, bool include_guid) const { ExtensionId extension_id = GetExtensionIdByURL(url); if (!extension_id.empty()) return include_guid ? GetByIDorGUID(extension_id) : GetByID(extension_id); // GetHostedAppByURL already supports filesystem: URLs (via MatchesURL). // TODO(crbug.com/41394231): Add support for blob: URLs in MatchesURL. return GetHostedAppByURL(url); } const Extension* ExtensionSet::GetAppByURL(const GURL& url) const { const Extension* extension = GetExtensionOrAppByURL(url); return (extension && extension->is_app()) ? extension : nullptr; } const Extension* ExtensionSet::GetHostedAppByURL(const GURL& url) const { auto hosted_app_itr = std::ranges::find_if(extensions_, [&](const auto& extension_info) { return extension_info.second->web_extent().MatchesURL(url); }); return hosted_app_itr != extensions_.end() ? hosted_app_itr->second.get() : nullptr; } const Extension* ExtensionSet::GetHostedAppByOverlappingWebExtent( const URLPatternSet& extent) const { auto hosted_app_itr = std::ranges::find_if(extensions_, [&](const auto& extension_info) { return extension_info.second->web_extent().OverlapsWith(extent); }); return hosted_app_itr != extensions_.end() ? hosted_app_itr->second.get() : nullptr; } bool ExtensionSet::InSameExtent(const GURL& old_url, const GURL& new_url) const { return GetExtensionOrAppByURL(old_url) == GetExtensionOrAppByURL(new_url); } const Extension* ExtensionSet::GetByID(const ExtensionId& id) const { return base::FindPtrOrNull(extensions_, id); } const Extension* ExtensionSet::GetByGUID(const std::string& guid) const { auto extension_itr = std::ranges::find( extensions_, guid, [](const auto& extension_info) { return extension_info.second->guid(); }); return extension_itr != extensions_.end() ? extension_itr->second.get() : nullptr; } const Extension* ExtensionSet::GetByIDorGUID( const std::string& id_or_guid) const { if (auto* extension = GetByID(id_or_guid)) return extension; return GetByGUID(id_or_guid); } ExtensionIdSet ExtensionSet::GetIDs() const { ExtensionIdSet ids; for (const auto& [extension_id, extension] : extensions_) { ids.insert(extension_id); } return ids; } bool ExtensionSet::ExtensionBindingsAllowed(const GURL& url) const { if (url.SchemeIs(kExtensionScheme)) return true; return std::ranges::any_of(extensions_, [&url](const auto& extension_info) { const Extension* extension = extension_info.second.get(); return extension->location() == mojom::ManifestLocation::kComponent && extension->web_extent().MatchesURL(url); }); } } // namespace extensions