Line data Source code
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/. */
5 :
6 : #ifndef mozilla_extensions_MatchPattern_h
7 : #define mozilla_extensions_MatchPattern_h
8 :
9 : #include "mozilla/dom/BindingDeclarations.h"
10 : #include "mozilla/dom/MatchPatternBinding.h"
11 : #include "mozilla/extensions/MatchGlob.h"
12 :
13 : #include "jspubtd.h"
14 :
15 : #include "mozilla/ClearOnShutdown.h"
16 : #include "mozilla/Likely.h"
17 : #include "mozilla/Maybe.h"
18 : #include "mozilla/RefCounted.h"
19 : #include "nsCOMPtr.h"
20 : #include "nsCycleCollectionParticipant.h"
21 : #include "nsTArray.h"
22 : #include "nsIAtom.h"
23 : #include "nsICookie2.h"
24 : #include "nsISupports.h"
25 : #include "nsIURI.h"
26 : #include "nsWrapperCache.h"
27 :
28 :
29 : namespace mozilla {
30 : namespace extensions {
31 :
32 : using dom::MatchPatternOptions;
33 :
34 :
35 : // A sorted, binary-search-backed set of atoms, optimized for frequent lookups
36 : // and infrequent updates.
37 0 : class AtomSet final : public RefCounted<AtomSet>
38 : {
39 : using ArrayType = AutoTArray<RefPtr<nsIAtom>, 1>;
40 :
41 : public:
42 0 : MOZ_DECLARE_REFCOUNTED_TYPENAME(AtomSet)
43 :
44 : explicit AtomSet(const nsTArray<nsString>& aElems);
45 :
46 : explicit AtomSet(const char** aElems);
47 :
48 : MOZ_IMPLICIT AtomSet(std::initializer_list<nsIAtom*> aIL);
49 :
50 0 : bool Contains(const nsAString& elem) const
51 : {
52 0 : nsCOMPtr<nsIAtom> atom = NS_AtomizeMainThread(elem);
53 0 : return Contains(atom);
54 : }
55 :
56 : bool Contains(const nsACString& aElem) const
57 : {
58 : nsCOMPtr<nsIAtom> atom = NS_Atomize(aElem);
59 : return Contains(atom);
60 : }
61 :
62 0 : bool Contains(const nsIAtom* aAtom) const
63 : {
64 0 : return mElems.BinaryIndexOf(aAtom) != mElems.NoIndex;
65 : }
66 :
67 : bool Intersects(const AtomSet& aOther) const;
68 :
69 :
70 : void Add(nsIAtom* aElem);
71 : void Remove(nsIAtom* aElem);
72 :
73 : void Add(const nsAString& aElem)
74 : {
75 : nsCOMPtr<nsIAtom> atom = NS_AtomizeMainThread(aElem);
76 : return Add(atom);
77 : }
78 :
79 : void Remove(const nsAString& aElem)
80 : {
81 : nsCOMPtr<nsIAtom> atom = NS_AtomizeMainThread(aElem);
82 : return Remove(atom);
83 : }
84 :
85 : // Returns a cached, statically-allocated matcher for the given set of
86 : // literal strings.
87 : template <const char** schemes>
88 : static already_AddRefed<AtomSet>
89 0 : Get()
90 : {
91 0 : static RefPtr<AtomSet> sMatcher;
92 :
93 0 : if (MOZ_UNLIKELY(!sMatcher)) {
94 0 : sMatcher = new AtomSet(schemes);
95 0 : ClearOnShutdown(&sMatcher);
96 : }
97 :
98 0 : return do_AddRef(sMatcher);
99 : }
100 :
101 : void
102 0 : Get(nsTArray<nsString>& aResult) const
103 : {
104 0 : aResult.SetCapacity(mElems.Length());
105 :
106 0 : for (const auto& atom : mElems) {
107 0 : aResult.AppendElement(nsDependentAtomString(atom));
108 : }
109 0 : }
110 :
111 0 : auto begin() const
112 : -> decltype(DeclVal<const ArrayType>().begin())
113 : {
114 0 : return mElems.begin();
115 : }
116 :
117 0 : auto end() const
118 : -> decltype(DeclVal<const ArrayType>().end())
119 : {
120 0 : return mElems.end();
121 : }
122 :
123 : private:
124 : ArrayType mElems;
125 :
126 : void SortAndUniquify();
127 : };
128 :
129 :
130 : // A helper class to lazily retrieve, transcode, and atomize certain URI
131 : // properties the first time they're used, and cache the results, so that they
132 : // can be used across multiple match operations.
133 0 : class MOZ_STACK_CLASS URLInfo final
134 : {
135 : public:
136 0 : MOZ_IMPLICIT URLInfo(nsIURI* aURI)
137 0 : : mURI(aURI)
138 : {
139 0 : mHost.SetIsVoid(true);
140 0 : }
141 :
142 0 : URLInfo(const URLInfo& aOther)
143 0 : : URLInfo(aOther.mURI.get())
144 0 : {}
145 :
146 0 : nsIURI* URI() const { return mURI; }
147 :
148 : nsIAtom* Scheme() const;
149 : const nsCString& Host() const;
150 : const nsString& Path() const;
151 : const nsString& FilePath() const;
152 : const nsString& Spec() const;
153 :
154 : bool InheritsPrincipal() const;
155 :
156 : private:
157 : nsIURI* URINoRef() const;
158 :
159 : nsCOMPtr<nsIURI> mURI;
160 : mutable nsCOMPtr<nsIURI> mURINoRef;
161 :
162 : mutable nsCOMPtr<nsIAtom> mScheme;
163 : mutable nsCString mHost;
164 :
165 : mutable nsAutoString mPath;
166 : mutable nsAutoString mFilePath;
167 : mutable nsAutoString mSpec;
168 :
169 : mutable Maybe<bool> mInheritsPrincipal;
170 : };
171 :
172 :
173 : // Similar to URLInfo, but for cookies.
174 0 : class MOZ_STACK_CLASS CookieInfo final
175 : {
176 : public:
177 0 : MOZ_IMPLICIT CookieInfo(nsICookie2* aCookie)
178 0 : : mCookie(aCookie)
179 0 : {}
180 :
181 : bool IsSecure() const;
182 : bool IsDomain() const;
183 :
184 : const nsCString& Host() const;
185 : const nsCString& RawHost() const;
186 :
187 : private:
188 : nsCOMPtr<nsICookie2> mCookie;
189 :
190 : mutable Maybe<bool> mIsSecure;
191 : mutable Maybe<bool> mIsDomain;
192 :
193 : mutable nsCString mHost;
194 : mutable nsCString mRawHost;
195 : };
196 :
197 :
198 : class MatchPattern final : public nsISupports
199 : , public nsWrapperCache
200 : {
201 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
202 0 : NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MatchPattern)
203 :
204 : static already_AddRefed<MatchPattern>
205 : Constructor(dom::GlobalObject& aGlobal,
206 : const nsAString& aPattern,
207 : const MatchPatternOptions& aOptions,
208 : ErrorResult& aRv);
209 :
210 : bool Matches(const URLInfo& aURL, bool aExplicit = false) const;
211 :
212 : bool MatchesCookie(const CookieInfo& aCookie) const;
213 :
214 : bool MatchesDomain(const nsACString& aDomain) const;
215 :
216 : bool Subsumes(const MatchPattern& aPattern) const;
217 :
218 : bool Overlaps(const MatchPattern& aPattern) const;
219 :
220 0 : bool DomainIsWildcard() const
221 : {
222 0 : return mMatchSubdomain && mDomain.IsEmpty();
223 : }
224 :
225 0 : void GetPattern(nsAString& aPattern) const
226 : {
227 0 : aPattern = mPattern;
228 0 : }
229 :
230 0 : nsISupports* GetParentObject() const { return mParent; }
231 :
232 : virtual JSObject* WrapObject(JSContext* aCx, JS::HandleObject aGivenProto) override;
233 :
234 : protected:
235 0 : virtual ~MatchPattern() = default;
236 :
237 : private:
238 0 : explicit MatchPattern(nsISupports* aParent) : mParent(aParent) {}
239 :
240 : void Init(JSContext* aCx, const nsAString& aPattern, bool aIgnorePath, ErrorResult& aRv);
241 :
242 : bool SubsumesDomain(const MatchPattern& aPattern) const;
243 :
244 :
245 : nsCOMPtr<nsISupports> mParent;
246 :
247 : // The normalized match pattern string that this object represents.
248 : nsString mPattern;
249 :
250 : // The set of atomized URI schemes that this pattern matches.
251 : RefPtr<AtomSet> mSchemes;
252 :
253 : // The domain that this matcher matches. If mMatchSubdomain is false, only
254 : // matches the exact domain. If it's true, matches the domain or any
255 : // subdomain.
256 : //
257 : // For instance, "*.foo.com" gives mDomain = "foo.com" and mMatchSubdomain = true,
258 : // and matches "foo.com" or "bar.foo.com" but not "barfoo.com".
259 : //
260 : // While "foo.com" gives mDomain = "foo.com" and mMatchSubdomain = false,
261 : // and matches "foo.com" but not "bar.foo.com".
262 : nsCString mDomain;
263 : bool mMatchSubdomain = false;
264 :
265 : // The glob against which the URL path must match. If null, the path is
266 : // ignored entirely. If non-null, the path must match this glob.
267 : RefPtr<MatchGlob> mPath;
268 : };
269 :
270 :
271 : class MatchPatternSet final : public nsISupports
272 : , public nsWrapperCache
273 : {
274 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
275 0 : NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MatchPatternSet)
276 :
277 : using ArrayType = nsTArray<RefPtr<MatchPattern>>;
278 :
279 :
280 : static already_AddRefed<MatchPatternSet>
281 : Constructor(dom::GlobalObject& aGlobal,
282 : const nsTArray<dom::OwningStringOrMatchPattern>& aPatterns,
283 : const MatchPatternOptions& aOptions,
284 : ErrorResult& aRv);
285 :
286 :
287 : bool Matches(const URLInfo& aURL, bool aExplicit = false) const;
288 :
289 : bool MatchesCookie(const CookieInfo& aCookie) const;
290 :
291 : bool Subsumes(const MatchPattern& aPattern) const;
292 :
293 : bool Overlaps(const MatchPattern& aPattern) const;
294 :
295 : bool Overlaps(const MatchPatternSet& aPatternSet) const;
296 :
297 : bool OverlapsAll(const MatchPatternSet& aPatternSet) const;
298 :
299 0 : void GetPatterns(ArrayType& aPatterns)
300 : {
301 0 : aPatterns.AppendElements(mPatterns);
302 0 : }
303 :
304 :
305 0 : nsISupports* GetParentObject() const { return mParent; }
306 :
307 : virtual JSObject* WrapObject(JSContext* aCx, JS::HandleObject aGivenProto) override;
308 :
309 : protected:
310 0 : virtual ~MatchPatternSet() = default;
311 :
312 : private:
313 0 : explicit MatchPatternSet(nsISupports* aParent, ArrayType&& aPatterns)
314 0 : : mParent(aParent)
315 0 : , mPatterns(Forward<ArrayType>(aPatterns))
316 0 : {}
317 :
318 : nsCOMPtr<nsISupports> mParent;
319 :
320 : ArrayType mPatterns;
321 : };
322 :
323 : } // namespace extensions
324 : } // namespace mozilla
325 :
326 : #endif // mozilla_extensions_MatchPattern_h
|