Bug 1805526 - Refactor extension.startup() permissions setup, r=robwu
[gecko.git] / toolkit / components / extensions / MatchPattern.h
blobf0f752fa45fe66278d2d02a28bab3a3753c2b435
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef mozilla_extensions_MatchPattern_h
7 #define mozilla_extensions_MatchPattern_h
9 #include <utility>
11 #include "mozilla/dom/BindingDeclarations.h"
12 #include "mozilla/dom/MatchPatternBinding.h"
13 #include "mozilla/extensions/MatchGlob.h"
15 #include "jspubtd.h"
17 #include "mozilla/ClearOnShutdown.h"
18 #include "mozilla/Likely.h"
19 #include "mozilla/Maybe.h"
20 #include "mozilla/RefCounted.h"
21 #include "nsCOMPtr.h"
22 #include "nsCycleCollectionParticipant.h"
23 #include "nsTArray.h"
24 #include "nsAtom.h"
25 #include "nsICookie.h"
26 #include "nsISupports.h"
27 #include "nsIURI.h"
28 #include "nsWrapperCache.h"
30 namespace mozilla {
31 namespace extensions {
33 using dom::MatchPatternOptions;
35 // A sorted, immutable, binary-search-backed set of atoms, optimized for
36 // frequent lookups.
37 class AtomSet final {
38 public:
39 using ArrayType = AutoTArray<RefPtr<nsAtom>, 1>;
41 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AtomSet)
43 explicit AtomSet(const nsTArray<nsString>& aElems);
45 MOZ_IMPLICIT AtomSet(std::initializer_list<nsAtom*> aIL);
47 bool Contains(const nsAString& elem) const {
48 RefPtr<nsAtom> atom = NS_Atomize(elem);
49 return Contains(atom);
52 bool Contains(const nsACString& aElem) const {
53 RefPtr<nsAtom> atom = NS_Atomize(aElem);
54 return Contains(atom);
57 bool Contains(const nsAtom* aAtom) const {
58 return mElems.ContainsSorted(aAtom);
61 bool Intersects(const AtomSet& aOther) const;
63 void Get(nsTArray<nsString>& aResult) const {
64 aResult.SetCapacity(mElems.Length());
66 for (const auto& atom : mElems) {
67 aResult.AppendElement(nsDependentAtomString(atom));
71 auto begin() const -> decltype(std::declval<const ArrayType>().begin()) {
72 return mElems.begin();
75 auto end() const -> decltype(std::declval<const ArrayType>().end()) {
76 return mElems.end();
79 private:
80 ~AtomSet() = default;
82 const ArrayType mElems;
85 // A helper class to lazily retrieve, transcode, and atomize certain URI
86 // properties the first time they're used, and cache the results, so that they
87 // can be used across multiple match operations.
88 class URLInfo final {
89 public:
90 MOZ_IMPLICIT URLInfo(nsIURI* aURI) : mURI(aURI) { mHost.SetIsVoid(true); }
92 URLInfo(nsIURI* aURI, bool aNoRef) : URLInfo(aURI) {
93 if (aNoRef) {
94 mURINoRef = mURI;
98 URLInfo(const URLInfo& aOther) : URLInfo(aOther.mURI.get()) {}
100 nsIURI* URI() const { return mURI; }
102 nsAtom* Scheme() const;
103 const nsCString& Host() const;
104 const nsAtom* HostAtom() const;
105 const nsCString& Path() const;
106 const nsCString& FilePath() const;
107 const nsString& Spec() const;
108 const nsCString& CSpec() const;
110 bool InheritsPrincipal() const;
112 private:
113 nsIURI* URINoRef() const;
115 nsCOMPtr<nsIURI> mURI;
116 mutable nsCOMPtr<nsIURI> mURINoRef;
118 mutable RefPtr<nsAtom> mScheme;
119 mutable nsCString mHost;
120 mutable RefPtr<nsAtom> mHostAtom;
122 mutable nsCString mPath;
123 mutable nsCString mFilePath;
124 mutable nsString mSpec;
125 mutable nsCString mCSpec;
127 mutable Maybe<bool> mInheritsPrincipal;
130 // Similar to URLInfo, but for cookies.
131 class MOZ_STACK_CLASS CookieInfo final {
132 public:
133 MOZ_IMPLICIT CookieInfo(nsICookie* aCookie) : mCookie(aCookie) {}
135 bool IsSecure() const;
136 bool IsDomain() const;
138 const nsCString& Host() const;
139 const nsCString& RawHost() const;
141 private:
142 nsCOMPtr<nsICookie> mCookie;
144 mutable Maybe<bool> mIsSecure;
145 mutable Maybe<bool> mIsDomain;
147 mutable nsCString mHost;
148 mutable nsCString mRawHost;
151 class MatchPatternCore final {
152 public:
153 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MatchPatternCore)
155 // NOTE: Must be constructed on the main thread!
156 MatchPatternCore(const nsAString& aPattern, bool aIgnorePath,
157 bool aRestrictSchemes, ErrorResult& aRv);
159 bool Matches(const nsAString& aURL, bool aExplicit, ErrorResult& aRv) const;
161 bool Matches(const URLInfo& aURL, bool aExplicit = false) const;
163 bool MatchesCookie(const CookieInfo& aCookie) const;
165 bool MatchesDomain(const nsACString& aDomain) const;
167 bool Subsumes(const MatchPatternCore& aPattern) const;
169 bool SubsumesDomain(const MatchPatternCore& aPattern) const;
171 bool Overlaps(const MatchPatternCore& aPattern) const;
173 bool DomainIsWildcard() const { return mMatchSubdomain && mDomain.IsEmpty(); }
175 void GetPattern(nsAString& aPattern) const { aPattern = mPattern; }
177 private:
178 ~MatchPatternCore() = default;
180 // The normalized match pattern string that this object represents.
181 nsString mPattern;
183 // The set of atomized URI schemes that this pattern matches.
184 RefPtr<AtomSet> mSchemes;
186 // The domain that this matcher matches. If mMatchSubdomain is false, only
187 // matches the exact domain. If it's true, matches the domain or any
188 // subdomain.
190 // For instance, "*.foo.com" gives mDomain = "foo.com" and mMatchSubdomain =
191 // true, and matches "foo.com" or "bar.foo.com" but not "barfoo.com".
193 // While "foo.com" gives mDomain = "foo.com" and mMatchSubdomain = false,
194 // and matches "foo.com" but not "bar.foo.com".
195 nsCString mDomain;
196 bool mMatchSubdomain = false;
198 // The glob against which the URL path must match. If null, the path is
199 // ignored entirely. If non-null, the path must match this glob.
200 RefPtr<MatchGlobCore> mPath;
203 class MatchPattern final : public nsISupports, public nsWrapperCache {
204 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
205 NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(MatchPattern)
207 static already_AddRefed<MatchPattern> Constructor(
208 dom::GlobalObject& aGlobal, const nsAString& aPattern,
209 const MatchPatternOptions& aOptions, ErrorResult& aRv);
211 bool Matches(const nsAString& aURL, bool aExplicit, ErrorResult& aRv) const {
212 return Core()->Matches(aURL, aExplicit, aRv);
215 bool Matches(const URLInfo& aURL, bool aExplicit = false) const {
216 return Core()->Matches(aURL, aExplicit);
219 bool Matches(const URLInfo& aURL, bool aExplicit, ErrorResult& aRv) const {
220 return Matches(aURL, aExplicit);
223 bool MatchesCookie(const CookieInfo& aCookie) const {
224 return Core()->MatchesCookie(aCookie);
227 bool MatchesDomain(const nsACString& aDomain) const {
228 return Core()->MatchesDomain(aDomain);
231 bool Subsumes(const MatchPattern& aPattern) const {
232 return Core()->Subsumes(*aPattern.Core());
235 bool SubsumesDomain(const MatchPattern& aPattern) const {
236 return Core()->SubsumesDomain(*aPattern.Core());
239 bool Overlaps(const MatchPattern& aPattern) const {
240 return Core()->Overlaps(*aPattern.Core());
243 bool DomainIsWildcard() const { return Core()->DomainIsWildcard(); }
245 void GetPattern(nsAString& aPattern) const { Core()->GetPattern(aPattern); }
247 MatchPatternCore* Core() const { return mCore; }
249 nsISupports* GetParentObject() const { return mParent; }
251 virtual JSObject* WrapObject(JSContext* aCx,
252 JS::Handle<JSObject*> aGivenProto) override;
254 protected:
255 virtual ~MatchPattern() = default;
257 private:
258 friend class MatchPatternSet;
260 explicit MatchPattern(nsISupports* aParent,
261 already_AddRefed<MatchPatternCore> aCore)
262 : mParent(aParent), mCore(std::move(aCore)) {}
264 void Init(JSContext* aCx, const nsAString& aPattern, bool aIgnorePath,
265 bool aRestrictSchemes, ErrorResult& aRv);
267 nsCOMPtr<nsISupports> mParent;
269 RefPtr<MatchPatternCore> mCore;
271 public:
272 // A quick way to check if a particular URL matches <all_urls> without
273 // actually instantiating a MatchPattern
274 static bool MatchesAllURLs(const URLInfo& aURL);
277 class MatchPatternSetCore final {
278 public:
279 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MatchPatternSetCore)
281 using ArrayType = nsTArray<RefPtr<MatchPatternCore>>;
283 explicit MatchPatternSetCore(ArrayType&& aPatterns)
284 : mPatterns(std::move(aPatterns)) {}
286 static already_AddRefed<MatchPatternSet> Constructor(
287 dom::GlobalObject& aGlobal,
288 const nsTArray<dom::OwningStringOrMatchPattern>& aPatterns,
289 const MatchPatternOptions& aOptions, ErrorResult& aRv);
291 bool Matches(const nsAString& aURL, bool aExplicit, ErrorResult& aRv) const;
293 bool Matches(const URLInfo& aURL, bool aExplicit = false) const;
295 bool MatchesCookie(const CookieInfo& aCookie) const;
297 bool Subsumes(const MatchPatternCore& aPattern) const;
299 bool SubsumesDomain(const MatchPatternCore& aPattern) const;
301 bool Overlaps(const MatchPatternCore& aPattern) const;
303 bool Overlaps(const MatchPatternSetCore& aPatternSet) const;
305 bool OverlapsAll(const MatchPatternSetCore& aPatternSet) const;
307 void GetPatterns(ArrayType& aPatterns) {
308 aPatterns.AppendElements(mPatterns);
311 private:
312 friend class MatchPatternSet;
314 ~MatchPatternSetCore() = default;
316 ArrayType mPatterns;
319 class MatchPatternSet final : public nsISupports, public nsWrapperCache {
320 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
321 NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(MatchPatternSet)
323 using ArrayType = nsTArray<RefPtr<MatchPattern>>;
325 static already_AddRefed<MatchPatternSet> Constructor(
326 dom::GlobalObject& aGlobal,
327 const nsTArray<dom::OwningStringOrMatchPattern>& aPatterns,
328 const MatchPatternOptions& aOptions, ErrorResult& aRv);
330 bool Matches(const nsAString& aURL, bool aExplicit, ErrorResult& aRv) const {
331 return Core()->Matches(aURL, aExplicit, aRv);
334 bool Matches(const URLInfo& aURL, bool aExplicit = false) const {
335 return Core()->Matches(aURL, aExplicit);
338 bool Matches(const URLInfo& aURL, bool aExplicit, ErrorResult& aRv) const {
339 return Matches(aURL, aExplicit);
342 bool MatchesCookie(const CookieInfo& aCookie) const {
343 return Core()->MatchesCookie(aCookie);
346 bool Subsumes(const MatchPattern& aPattern) const {
347 return Core()->Subsumes(*aPattern.Core());
350 bool SubsumesDomain(const MatchPattern& aPattern) const {
351 return Core()->SubsumesDomain(*aPattern.Core());
354 bool Overlaps(const MatchPattern& aPattern) const {
355 return Core()->Overlaps(*aPattern.Core());
358 bool Overlaps(const MatchPatternSet& aPatternSet) const {
359 return Core()->Overlaps(*aPatternSet.Core());
362 bool OverlapsAll(const MatchPatternSet& aPatternSet) const {
363 return Core()->OverlapsAll(*aPatternSet.Core());
366 void GetPatterns(ArrayType& aPatterns);
368 MatchPatternSetCore* Core() const { return mCore; }
370 nsISupports* GetParentObject() const { return mParent; }
372 virtual JSObject* WrapObject(JSContext* aCx,
373 JS::Handle<JSObject*> aGivenProto) override;
375 protected:
376 virtual ~MatchPatternSet() = default;
378 private:
379 explicit MatchPatternSet(nsISupports* aParent,
380 already_AddRefed<MatchPatternSetCore> aCore)
381 : mParent(aParent), mCore(std::move(aCore)) {}
383 nsCOMPtr<nsISupports> mParent;
385 RefPtr<MatchPatternSetCore> mCore;
387 mozilla::Maybe<ArrayType> mPatternsCache;
390 } // namespace extensions
391 } // namespace mozilla
393 #endif // mozilla_extensions_MatchPattern_h