1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "extensions/common/extension_set.h"
6 
7 #include "extensions/common/constants.h"
8 #include "extensions/common/url_pattern_set.h"
9 #include "url/gurl.h"
10 #include "url/origin.h"
11 
12 namespace extensions {
13 
14 namespace {
15 
GetExtensionIdByURL(const GURL & url)16 ExtensionId GetExtensionIdByURL(const GURL& url) {
17   if (url.SchemeIs(kExtensionScheme))
18     return url.host();
19 
20   // Trying url::Origin is important to properly handle extension schemes inside
21   // blob: and filesystem: URLs, which won't match the extension scheme check
22   // above.
23   url::Origin origin = url::Origin::Create(url);
24   if (origin.scheme() == kExtensionScheme)
25     return origin.host();
26 
27   return ExtensionId();
28 }
29 
30 }  // namespace
31 
const_iterator()32 ExtensionSet::const_iterator::const_iterator() {}
33 
const_iterator(const const_iterator & other)34 ExtensionSet::const_iterator::const_iterator(const const_iterator& other)
35     : it_(other.it_) {
36 }
37 
const_iterator(ExtensionMap::const_iterator it)38 ExtensionSet::const_iterator::const_iterator(ExtensionMap::const_iterator it)
39     : it_(it) {
40 }
41 
~const_iterator()42 ExtensionSet::const_iterator::~const_iterator() {}
43 
ExtensionSet()44 ExtensionSet::ExtensionSet() {
45 }
46 
~ExtensionSet()47 ExtensionSet::~ExtensionSet() {
48 }
49 
size() const50 size_t ExtensionSet::size() const {
51   return extensions_.size();
52 }
53 
is_empty() const54 bool ExtensionSet::is_empty() const {
55   return extensions_.empty();
56 }
57 
Contains(const ExtensionId & extension_id) const58 bool ExtensionSet::Contains(const ExtensionId& extension_id) const {
59   return extensions_.find(extension_id) != extensions_.end();
60 }
61 
Insert(const scoped_refptr<const Extension> & extension)62 bool ExtensionSet::Insert(const scoped_refptr<const Extension>& extension) {
63   auto iter = extensions_.find(extension->id());
64   if (iter != extensions_.end()) {
65     iter->second = extension;
66     return false;  // Had a previous entry.
67   }
68   extensions_.emplace(extension->id(), extension);
69   return true;  // New entry added.
70 }
71 
InsertAll(const ExtensionSet & extensions)72 bool ExtensionSet::InsertAll(const ExtensionSet& extensions) {
73   size_t before = size();
74   for (ExtensionSet::const_iterator iter = extensions.begin();
75        iter != extensions.end(); ++iter) {
76     Insert(*iter);
77   }
78   return size() != before;
79 }
80 
Remove(const ExtensionId & id)81 bool ExtensionSet::Remove(const ExtensionId& id) {
82   return extensions_.erase(id) > 0;
83 }
84 
Clear()85 void ExtensionSet::Clear() {
86   extensions_.clear();
87 }
88 
GetExtensionOrAppIDByURL(const GURL & url) const89 ExtensionId ExtensionSet::GetExtensionOrAppIDByURL(const GURL& url) const {
90   ExtensionId extension_id = GetExtensionIdByURL(url);
91   if (!extension_id.empty())
92     return extension_id;
93 
94   // GetHostedAppByURL already supports filesystem: URLs (via MatchesURL).
95   // TODO(crbug/852162): Add support for blob: URLs in MatchesURL.
96   const Extension* extension = GetHostedAppByURL(url);
97   if (!extension)
98     return ExtensionId();
99 
100   return extension->id();
101 }
102 
GetExtensionOrAppByURL(const GURL & url) const103 const Extension* ExtensionSet::GetExtensionOrAppByURL(const GURL& url) const {
104   ExtensionId extension_id = GetExtensionIdByURL(url);
105   if (!extension_id.empty())
106     return GetByID(extension_id);
107 
108   // GetHostedAppByURL already supports filesystem: URLs (via MatchesURL).
109   // TODO(crbug/852162): Add support for blob: URLs in MatchesURL.
110   return GetHostedAppByURL(url);
111 }
112 
GetAppByURL(const GURL & url) const113 const Extension* ExtensionSet::GetAppByURL(const GURL& url) const {
114   const Extension* extension = GetExtensionOrAppByURL(url);
115   return (extension && extension->is_app()) ? extension : NULL;
116 }
117 
GetHostedAppByURL(const GURL & url) const118 const Extension* ExtensionSet::GetHostedAppByURL(const GURL& url) const {
119   for (auto iter = extensions_.cbegin(); iter != extensions_.cend(); ++iter) {
120     if (iter->second->web_extent().MatchesURL(url))
121       return iter->second.get();
122   }
123 
124   return NULL;
125 }
126 
GetHostedAppByOverlappingWebExtent(const URLPatternSet & extent) const127 const Extension* ExtensionSet::GetHostedAppByOverlappingWebExtent(
128     const URLPatternSet& extent) const {
129   for (auto iter = extensions_.cbegin(); iter != extensions_.cend(); ++iter) {
130     if (iter->second->web_extent().OverlapsWith(extent))
131       return iter->second.get();
132   }
133 
134   return NULL;
135 }
136 
InSameExtent(const GURL & old_url,const GURL & new_url) const137 bool ExtensionSet::InSameExtent(const GURL& old_url,
138                                 const GURL& new_url) const {
139   return GetExtensionOrAppByURL(old_url) ==
140       GetExtensionOrAppByURL(new_url);
141 }
142 
GetByID(const ExtensionId & id) const143 const Extension* ExtensionSet::GetByID(const ExtensionId& id) const {
144   auto i = extensions_.find(id);
145   if (i != extensions_.end())
146     return i->second.get();
147   return nullptr;
148 }
149 
GetIDs() const150 ExtensionIdSet ExtensionSet::GetIDs() const {
151   ExtensionIdSet ids;
152   for (auto it = extensions_.cbegin(); it != extensions_.cend(); ++it) {
153     ids.insert(it->first);
154   }
155   return ids;
156 }
157 
ExtensionBindingsAllowed(const GURL & url) const158 bool ExtensionSet::ExtensionBindingsAllowed(const GURL& url) const {
159   if (url.SchemeIs(kExtensionScheme))
160     return true;
161 
162   for (auto it = extensions_.cbegin(); it != extensions_.cend(); ++it) {
163     if (it->second->location() == Manifest::COMPONENT &&
164         it->second->web_extent().MatchesURL(url))
165       return true;
166   }
167 
168   return false;
169 }
170 
171 }  // namespace extensions
172