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
11 #include "mozilla/dom/BindingDeclarations.h"
12 #include "mozilla/dom/MatchPatternBinding.h"
13 #include "mozilla/extensions/MatchGlob.h"
17 #include "mozilla/ClearOnShutdown.h"
18 #include "mozilla/Likely.h"
19 #include "mozilla/Maybe.h"
20 #include "mozilla/RefCounted.h"
22 #include "nsCycleCollectionParticipant.h"
25 #include "nsICookie.h"
26 #include "nsISupports.h"
28 #include "nsWrapperCache.h"
31 namespace extensions
{
33 using dom::MatchPatternOptions
;
35 // A sorted, immutable, binary-search-backed set of atoms, optimized for
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()) {
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.
90 MOZ_IMPLICIT
URLInfo(nsIURI
* aURI
) : mURI(aURI
) { mHost
.SetIsVoid(true); }
92 URLInfo(nsIURI
* aURI
, bool aNoRef
) : URLInfo(aURI
) {
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;
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
{
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;
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
{
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 MatchesAllWebUrls() const;
164 // Helper for MatchPatternSetCore::MatchesAllWebUrls:
165 bool MatchesAllUrlsWithScheme(const nsAtom
* aScheme
) const;
167 bool MatchesCookie(const CookieInfo
& aCookie
) const;
169 bool MatchesDomain(const nsACString
& aDomain
) const;
171 bool Subsumes(const MatchPatternCore
& aPattern
) const;
173 bool SubsumesDomain(const MatchPatternCore
& aPattern
) const;
175 bool Overlaps(const MatchPatternCore
& aPattern
) const;
177 bool DomainIsWildcard() const { return mMatchSubdomain
&& mDomain
.IsEmpty(); }
179 void GetPattern(nsAString
& aPattern
) const { aPattern
= mPattern
; }
182 ~MatchPatternCore() = default;
184 // The normalized match pattern string that this object represents.
187 // The set of atomized URI schemes that this pattern matches.
188 RefPtr
<AtomSet
> mSchemes
;
190 // The domain that this matcher matches. If mMatchSubdomain is false, only
191 // matches the exact domain. If it's true, matches the domain or any
194 // For instance, "*.foo.com" gives mDomain = "foo.com" and mMatchSubdomain =
195 // true, and matches "foo.com" or "bar.foo.com" but not "barfoo.com".
197 // While "foo.com" gives mDomain = "foo.com" and mMatchSubdomain = false,
198 // and matches "foo.com" but not "bar.foo.com".
200 bool mMatchSubdomain
= false;
202 // The glob against which the URL path must match. If null, the path is
203 // ignored entirely. If non-null, the path must match this glob.
204 RefPtr
<MatchGlobCore
> mPath
;
207 class MatchPattern final
: public nsISupports
, public nsWrapperCache
{
208 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
209 NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(MatchPattern
)
211 static already_AddRefed
<MatchPattern
> Constructor(
212 dom::GlobalObject
& aGlobal
, const nsAString
& aPattern
,
213 const MatchPatternOptions
& aOptions
, ErrorResult
& aRv
);
215 bool Matches(const nsAString
& aURL
, bool aExplicit
, ErrorResult
& aRv
) const {
216 return Core()->Matches(aURL
, aExplicit
, aRv
);
219 bool MatchesAllWebUrls() const { return Core()->MatchesAllWebUrls(); }
221 bool Matches(const URLInfo
& aURL
, bool aExplicit
= false) const {
222 return Core()->Matches(aURL
, aExplicit
);
225 bool Matches(const URLInfo
& aURL
, bool aExplicit
, ErrorResult
& aRv
) const {
226 return Matches(aURL
, aExplicit
);
229 bool MatchesCookie(const CookieInfo
& aCookie
) const {
230 return Core()->MatchesCookie(aCookie
);
233 bool MatchesDomain(const nsACString
& aDomain
) const {
234 return Core()->MatchesDomain(aDomain
);
237 bool Subsumes(const MatchPattern
& aPattern
) const {
238 return Core()->Subsumes(*aPattern
.Core());
241 bool SubsumesDomain(const MatchPattern
& aPattern
) const {
242 return Core()->SubsumesDomain(*aPattern
.Core());
245 bool Overlaps(const MatchPattern
& aPattern
) const {
246 return Core()->Overlaps(*aPattern
.Core());
249 bool DomainIsWildcard() const { return Core()->DomainIsWildcard(); }
251 void GetPattern(nsAString
& aPattern
) const { Core()->GetPattern(aPattern
); }
253 MatchPatternCore
* Core() const { return mCore
; }
255 nsISupports
* GetParentObject() const { return mParent
; }
257 virtual JSObject
* WrapObject(JSContext
* aCx
,
258 JS::Handle
<JSObject
*> aGivenProto
) override
;
261 virtual ~MatchPattern() = default;
264 friend class MatchPatternSet
;
266 explicit MatchPattern(nsISupports
* aParent
,
267 already_AddRefed
<MatchPatternCore
> aCore
)
268 : mParent(aParent
), mCore(std::move(aCore
)) {}
270 void Init(JSContext
* aCx
, const nsAString
& aPattern
, bool aIgnorePath
,
271 bool aRestrictSchemes
, ErrorResult
& aRv
);
273 nsCOMPtr
<nsISupports
> mParent
;
275 RefPtr
<MatchPatternCore
> mCore
;
278 // A quick way to check if a particular URL matches <all_urls> without
279 // actually instantiating a MatchPattern
280 static bool MatchesAllURLs(const URLInfo
& aURL
);
283 class MatchPatternSetCore final
{
285 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MatchPatternSetCore
)
287 using ArrayType
= nsTArray
<RefPtr
<MatchPatternCore
>>;
289 explicit MatchPatternSetCore(ArrayType
&& aPatterns
)
290 : mPatterns(std::move(aPatterns
)) {}
292 static already_AddRefed
<MatchPatternSet
> Constructor(
293 dom::GlobalObject
& aGlobal
,
294 const nsTArray
<dom::OwningStringOrMatchPattern
>& aPatterns
,
295 const MatchPatternOptions
& aOptions
, ErrorResult
& aRv
);
297 bool Matches(const nsAString
& aURL
, bool aExplicit
, ErrorResult
& aRv
) const;
299 bool Matches(const URLInfo
& aURL
, bool aExplicit
= false) const;
301 bool MatchesAllWebUrls() const;
303 bool MatchesCookie(const CookieInfo
& aCookie
) const;
305 bool Subsumes(const MatchPatternCore
& aPattern
) const;
307 bool SubsumesDomain(const MatchPatternCore
& aPattern
) const;
309 bool Overlaps(const MatchPatternCore
& aPattern
) const;
311 bool Overlaps(const MatchPatternSetCore
& aPatternSet
) const;
313 bool OverlapsAll(const MatchPatternSetCore
& aPatternSet
) const;
315 void GetPatterns(ArrayType
& aPatterns
) {
316 aPatterns
.AppendElements(mPatterns
);
320 friend class MatchPatternSet
;
322 ~MatchPatternSetCore() = default;
327 class MatchPatternSet final
: public nsISupports
, public nsWrapperCache
{
328 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
329 NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(MatchPatternSet
)
331 using ArrayType
= nsTArray
<RefPtr
<MatchPattern
>>;
333 static already_AddRefed
<MatchPatternSet
> Constructor(
334 dom::GlobalObject
& aGlobal
,
335 const nsTArray
<dom::OwningStringOrMatchPattern
>& aPatterns
,
336 const MatchPatternOptions
& aOptions
, ErrorResult
& aRv
);
338 bool Matches(const nsAString
& aURL
, bool aExplicit
, ErrorResult
& aRv
) const {
339 return Core()->Matches(aURL
, aExplicit
, aRv
);
342 bool Matches(const URLInfo
& aURL
, bool aExplicit
= false) const {
343 return Core()->Matches(aURL
, aExplicit
);
346 bool Matches(const URLInfo
& aURL
, bool aExplicit
, ErrorResult
& aRv
) const {
347 return Matches(aURL
, aExplicit
);
350 bool MatchesAllWebUrls() const { return Core()->MatchesAllWebUrls(); }
352 bool MatchesCookie(const CookieInfo
& aCookie
) const {
353 return Core()->MatchesCookie(aCookie
);
356 bool Subsumes(const MatchPattern
& aPattern
) const {
357 return Core()->Subsumes(*aPattern
.Core());
360 bool SubsumesDomain(const MatchPattern
& aPattern
) const {
361 return Core()->SubsumesDomain(*aPattern
.Core());
364 bool Overlaps(const MatchPattern
& aPattern
) const {
365 return Core()->Overlaps(*aPattern
.Core());
368 bool Overlaps(const MatchPatternSet
& aPatternSet
) const {
369 return Core()->Overlaps(*aPatternSet
.Core());
372 bool OverlapsAll(const MatchPatternSet
& aPatternSet
) const {
373 return Core()->OverlapsAll(*aPatternSet
.Core());
376 void GetPatterns(ArrayType
& aPatterns
);
378 MatchPatternSetCore
* Core() const { return mCore
; }
380 nsISupports
* GetParentObject() const { return mParent
; }
382 virtual JSObject
* WrapObject(JSContext
* aCx
,
383 JS::Handle
<JSObject
*> aGivenProto
) override
;
386 virtual ~MatchPatternSet() = default;
389 explicit MatchPatternSet(nsISupports
* aParent
,
390 already_AddRefed
<MatchPatternSetCore
> aCore
)
391 : mParent(aParent
), mCore(std::move(aCore
)) {}
393 nsCOMPtr
<nsISupports
> mParent
;
395 RefPtr
<MatchPatternSetCore
> mCore
;
397 mozilla::Maybe
<ArrayType
> mPatternsCache
;
400 } // namespace extensions
401 } // namespace mozilla
403 #endif // mozilla_extensions_MatchPattern_h