blob: 18f74c1f0c20badd4931f6f7034f61662f9a6e76 [file] [log] [blame]
// 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<const Extension>& 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 =
base::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 =
base::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 = base::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 base::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