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 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
; }
178 ~MatchPatternCore() = default;
180 // The normalized match pattern string that this object represents.
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
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".
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
;
255 virtual ~MatchPattern() = default;
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
;
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
{
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
);
312 friend class MatchPatternSet
;
314 ~MatchPatternSetCore() = default;
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
;
376 virtual ~MatchPatternSet() = default;
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