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 file,
4 : * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "mozilla/extensions/MatchPattern.h"
7 : #include "mozilla/extensions/MatchGlob.h"
8 :
9 : #include "mozilla/dom/ScriptSettings.h"
10 : #include "mozilla/HoldDropJSObjects.h"
11 : #include "mozilla/Unused.h"
12 :
13 : #include "nsGkAtoms.h"
14 : #include "nsIProtocolHandler.h"
15 : #include "nsIURL.h"
16 : #include "nsNetUtil.h"
17 :
18 : namespace mozilla {
19 : namespace extensions {
20 :
21 : using namespace mozilla::dom;
22 :
23 :
24 : /*****************************************************************************
25 : * AtomSet
26 : *****************************************************************************/
27 :
28 0 : AtomSet::AtomSet(const nsTArray<nsString>& aElems)
29 : {
30 0 : mElems.SetCapacity(aElems.Length());
31 :
32 0 : for (const auto& elem : aElems) {
33 0 : mElems.AppendElement(NS_AtomizeMainThread(elem));
34 : }
35 :
36 0 : SortAndUniquify();
37 0 : }
38 :
39 0 : AtomSet::AtomSet(const char** aElems)
40 : {
41 0 : for (const char** elemp = aElems; *elemp; elemp++) {
42 0 : mElems.AppendElement(NS_Atomize(*elemp));
43 : }
44 :
45 0 : SortAndUniquify();
46 0 : }
47 :
48 0 : AtomSet::AtomSet(std::initializer_list<nsIAtom*> aIL)
49 : {
50 0 : mElems.SetCapacity(aIL.size());
51 :
52 0 : for (const auto& elem : aIL) {
53 0 : mElems.AppendElement(elem);
54 : }
55 :
56 0 : SortAndUniquify();
57 0 : }
58 :
59 : void
60 0 : AtomSet::SortAndUniquify()
61 : {
62 0 : mElems.Sort();
63 :
64 0 : nsIAtom* prev = nullptr;
65 0 : mElems.RemoveElementsBy([&prev] (const RefPtr<nsIAtom>& aAtom) {
66 0 : bool remove = aAtom == prev;
67 0 : prev = aAtom;
68 0 : return remove;
69 0 : });
70 :
71 0 : mElems.Compact();
72 0 : }
73 :
74 : bool
75 0 : AtomSet::Intersects(const AtomSet& aOther) const
76 : {
77 0 : for (const auto& atom : *this) {
78 0 : if (aOther.Contains(atom)) {
79 0 : return true;
80 : }
81 : }
82 0 : for (const auto& atom : aOther) {
83 0 : if (Contains(atom)) {
84 0 : return true;
85 : }
86 : }
87 0 : return false;
88 : }
89 :
90 : void
91 0 : AtomSet::Add(nsIAtom* aAtom)
92 : {
93 0 : auto index = mElems.IndexOfFirstElementGt(aAtom);
94 0 : if (index == 0 || mElems[index - 1] != aAtom) {
95 0 : mElems.InsertElementAt(index, aAtom);
96 : }
97 0 : }
98 :
99 : void
100 0 : AtomSet::Remove(nsIAtom* aAtom)
101 : {
102 0 : auto index = mElems.BinaryIndexOf(aAtom);
103 0 : if (index != mElems.NoIndex) {
104 0 : mElems.RemoveElementAt(index);
105 : }
106 0 : }
107 :
108 :
109 : /*****************************************************************************
110 : * URLInfo
111 : *****************************************************************************/
112 :
113 : nsIAtom*
114 0 : URLInfo::Scheme() const
115 : {
116 0 : if (!mScheme) {
117 0 : nsCString scheme;
118 0 : if (NS_SUCCEEDED(mURI->GetScheme(scheme))) {
119 0 : mScheme = NS_AtomizeMainThread(NS_ConvertASCIItoUTF16(scheme));
120 : }
121 : }
122 0 : return mScheme;
123 : }
124 :
125 : const nsCString&
126 0 : URLInfo::Host() const
127 : {
128 0 : if (mHost.IsVoid()) {
129 0 : Unused << mURI->GetHost(mHost);
130 : }
131 0 : return mHost;
132 : }
133 :
134 : const nsString&
135 0 : URLInfo::FilePath() const
136 : {
137 0 : if (mFilePath.IsEmpty()) {
138 0 : nsCString path;
139 0 : nsCOMPtr<nsIURL> url = do_QueryInterface(mURI);
140 0 : if (url && NS_SUCCEEDED(url->GetFilePath(path))) {
141 0 : AppendUTF8toUTF16(path, mFilePath);
142 : } else {
143 0 : mFilePath = Path();
144 : }
145 : }
146 0 : return mFilePath;
147 : }
148 :
149 : const nsString&
150 0 : URLInfo::Path() const
151 : {
152 0 : if (mPath.IsEmpty()) {
153 0 : nsCString path;
154 0 : if (NS_SUCCEEDED(URINoRef()->GetPath(path))) {
155 0 : AppendUTF8toUTF16(path, mPath);
156 : }
157 : }
158 0 : return mPath;
159 : }
160 :
161 : const nsString&
162 0 : URLInfo::Spec() const
163 : {
164 0 : if (mSpec.IsEmpty()) {
165 0 : nsCString spec;
166 0 : if (NS_SUCCEEDED(URINoRef()->GetSpec(spec))) {
167 0 : AppendUTF8toUTF16(spec, mSpec);
168 : }
169 : }
170 0 : return mSpec;
171 : }
172 :
173 : nsIURI*
174 0 : URLInfo::URINoRef() const
175 : {
176 0 : if (!mURINoRef) {
177 0 : if (NS_FAILED(mURI->CloneIgnoringRef(getter_AddRefs(mURINoRef)))) {
178 0 : mURINoRef = mURI;
179 : }
180 : }
181 0 : return mURINoRef;
182 : }
183 :
184 : bool
185 0 : URLInfo::InheritsPrincipal() const
186 : {
187 0 : if (!mInheritsPrincipal.isSome()) {
188 : // For our purposes, about:blank and about:srcdoc are treated as URIs that
189 : // inherit principals.
190 0 : bool inherits = Spec().EqualsLiteral("about:blank") || Spec().EqualsLiteral("about:srcdoc");
191 :
192 0 : if (!inherits) {
193 0 : nsresult rv = NS_URIChainHasFlags(mURI, nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
194 0 : &inherits);
195 0 : Unused << NS_WARN_IF(NS_FAILED(rv));
196 : }
197 :
198 0 : mInheritsPrincipal.emplace(inherits);
199 : }
200 0 : return mInheritsPrincipal.ref();
201 : }
202 :
203 :
204 : /*****************************************************************************
205 : * CookieInfo
206 : *****************************************************************************/
207 :
208 : bool
209 0 : CookieInfo::IsDomain() const
210 : {
211 0 : if (mIsDomain.isNothing()) {
212 0 : mIsDomain.emplace(false);
213 0 : MOZ_ALWAYS_SUCCEEDS(mCookie->GetIsDomain(mIsDomain.ptr()));
214 : }
215 0 : return mIsDomain.ref();
216 : }
217 :
218 : bool
219 0 : CookieInfo::IsSecure() const
220 : {
221 0 : if (mIsSecure.isNothing()) {
222 0 : mIsSecure.emplace(false);
223 0 : MOZ_ALWAYS_SUCCEEDS(mCookie->GetIsSecure(mIsSecure.ptr()));
224 : }
225 0 : return mIsSecure.ref();
226 : }
227 :
228 : const nsCString&
229 0 : CookieInfo::Host() const
230 : {
231 0 : if (mHost.IsEmpty()) {
232 0 : MOZ_ALWAYS_SUCCEEDS(mCookie->GetHost(mHost));
233 : }
234 0 : return mHost;
235 : }
236 :
237 : const nsCString&
238 0 : CookieInfo::RawHost() const
239 : {
240 0 : if (mRawHost.IsEmpty()) {
241 0 : MOZ_ALWAYS_SUCCEEDS(mCookie->GetRawHost(mRawHost));
242 : }
243 0 : return mRawHost;
244 : }
245 :
246 :
247 : /*****************************************************************************
248 : * MatchPattern
249 : *****************************************************************************/
250 :
251 : const char* PERMITTED_SCHEMES[] = {"http", "https", "ws", "wss", "file", "ftp", "data", nullptr};
252 :
253 : const char* WILDCARD_SCHEMES[] = {"http", "https", "ws", "wss", nullptr};
254 :
255 : /* static */ already_AddRefed<MatchPattern>
256 0 : MatchPattern::Constructor(dom::GlobalObject& aGlobal,
257 : const nsAString& aPattern,
258 : const MatchPatternOptions& aOptions,
259 : ErrorResult& aRv)
260 : {
261 0 : RefPtr<MatchPattern> pattern = new MatchPattern(aGlobal.GetAsSupports());
262 0 : pattern->Init(aGlobal.Context(), aPattern, aOptions.mIgnorePath, aRv);
263 0 : if (aRv.Failed()) {
264 0 : return nullptr;
265 : }
266 0 : return pattern.forget();
267 : }
268 :
269 : void
270 0 : MatchPattern::Init(JSContext* aCx, const nsAString& aPattern, bool aIgnorePath, ErrorResult& aRv)
271 : {
272 0 : RefPtr<AtomSet> permittedSchemes = AtomSet::Get<PERMITTED_SCHEMES>();
273 :
274 0 : mPattern = aPattern;
275 :
276 0 : if (aPattern.EqualsLiteral("<all_urls>")) {
277 0 : mSchemes = permittedSchemes;
278 0 : mMatchSubdomain = true;
279 0 : return;
280 : }
281 :
282 : // The portion of the URL we're currently examining.
283 0 : uint32_t offset = 0;
284 0 : auto tail = Substring(aPattern, offset);
285 :
286 : /***************************************************************************
287 : * Scheme
288 : ***************************************************************************/
289 0 : int32_t index = aPattern.FindChar(':');
290 0 : if (index <= 0) {
291 0 : aRv.Throw(NS_ERROR_INVALID_ARG);
292 0 : return;
293 : }
294 :
295 0 : nsCOMPtr<nsIAtom> scheme = NS_AtomizeMainThread(StringHead(aPattern, index));
296 0 : if (scheme == nsGkAtoms::_asterisk) {
297 0 : mSchemes = AtomSet::Get<WILDCARD_SCHEMES>();
298 0 : } else if (permittedSchemes->Contains(scheme) || scheme == nsGkAtoms::moz_extension) {
299 0 : mSchemes = new AtomSet({scheme});
300 : } else {
301 0 : aRv.Throw(NS_ERROR_INVALID_ARG);
302 0 : return;
303 : }
304 :
305 : /***************************************************************************
306 : * Host
307 : ***************************************************************************/
308 0 : offset = index + 1;
309 0 : tail.Rebind(aPattern, offset);
310 :
311 0 : if (!StringHead(tail, 2).EqualsLiteral("//")) {
312 0 : aRv.Throw(NS_ERROR_INVALID_ARG);
313 0 : return;
314 : }
315 :
316 0 : offset += 2;
317 0 : tail.Rebind(aPattern, offset);
318 0 : index = tail.FindChar('/');
319 0 : if (index < 0) {
320 0 : index = tail.Length();
321 : }
322 :
323 0 : auto host = StringHead(tail, index);
324 0 : if (host.IsEmpty() && scheme != nsGkAtoms::file) {
325 0 : aRv.Throw(NS_ERROR_INVALID_ARG);
326 0 : return;
327 : }
328 :
329 0 : offset += index;
330 0 : tail.Rebind(aPattern, offset);
331 :
332 0 : if (host.EqualsLiteral("*")) {
333 0 : mMatchSubdomain = true;
334 0 : } else if (StringHead(host, 2).EqualsLiteral("*.")) {
335 0 : mDomain = NS_ConvertUTF16toUTF8(Substring(host, 2));
336 0 : mMatchSubdomain = true;
337 : } else {
338 0 : mDomain = NS_ConvertUTF16toUTF8(host);
339 : }
340 :
341 : /***************************************************************************
342 : * Path
343 : ***************************************************************************/
344 0 : if (aIgnorePath) {
345 0 : mPattern.Truncate(offset);
346 0 : mPattern.AppendLiteral("/*");
347 0 : return;
348 : }
349 :
350 0 : auto path = tail;
351 0 : if (path.IsEmpty()) {
352 0 : aRv.Throw(NS_ERROR_INVALID_ARG);
353 0 : return;
354 : }
355 :
356 0 : mPath = new MatchGlob(this);
357 0 : mPath->Init(aCx, path, false, aRv);
358 : }
359 :
360 :
361 : bool
362 0 : MatchPattern::MatchesDomain(const nsACString& aDomain) const
363 : {
364 0 : if (DomainIsWildcard() || mDomain == aDomain) {
365 0 : return true;
366 : }
367 :
368 0 : if (mMatchSubdomain) {
369 0 : int64_t offset = (int64_t)aDomain.Length() - mDomain.Length();
370 0 : if (offset > 0 && aDomain[offset - 1] == '.' &&
371 0 : Substring(aDomain, offset) == mDomain) {
372 0 : return true;
373 : }
374 : }
375 :
376 0 : return false;
377 : }
378 :
379 : bool
380 0 : MatchPattern::Matches(const URLInfo& aURL, bool aExplicit) const
381 : {
382 0 : if (aExplicit && mMatchSubdomain) {
383 0 : return false;
384 : }
385 :
386 0 : if (!mSchemes->Contains(aURL.Scheme())) {
387 0 : return false;
388 : }
389 :
390 0 : if (!DomainIsWildcard() && !MatchesDomain(aURL.Host())) {
391 0 : return false;
392 : }
393 :
394 0 : if (mPath && !mPath->IsWildcard() && !mPath->Matches(aURL.Path())) {
395 0 : return false;
396 : }
397 :
398 0 : return true;
399 : }
400 :
401 : bool
402 0 : MatchPattern::MatchesCookie(const CookieInfo& aCookie) const
403 : {
404 0 : if (!mSchemes->Contains(nsGkAtoms::https) &&
405 0 : (aCookie.IsSecure() || !mSchemes->Contains(nsGkAtoms::http))) {
406 0 : return false;
407 : }
408 :
409 0 : if (MatchesDomain(aCookie.RawHost())) {
410 0 : return true;
411 : }
412 :
413 0 : if (!aCookie.IsDomain()) {
414 0 : return false;
415 : }
416 :
417 : // Things get tricker for domain cookies. The extension needs to be able
418 : // to read any cookies that could be read by any host it has permissions
419 : // for. This means that our normal host matching checks won't work,
420 : // since the pattern "*://*.foo.example.com/" doesn't match ".example.com",
421 : // but it does match "bar.foo.example.com", which can read cookies
422 : // with the domain ".example.com".
423 : //
424 : // So, instead, we need to manually check our filters, and accept any
425 : // with hosts that end with our cookie's host.
426 :
427 0 : auto& host = aCookie.Host();
428 0 : return StringTail(mDomain, host.Length()) == host;
429 : }
430 :
431 : bool
432 0 : MatchPattern::SubsumesDomain(const MatchPattern& aPattern) const
433 : {
434 0 : if (!mMatchSubdomain && aPattern.mMatchSubdomain && aPattern.mDomain == mDomain) {
435 0 : return false;
436 : }
437 :
438 0 : return MatchesDomain(aPattern.mDomain);
439 : }
440 :
441 : bool
442 0 : MatchPattern::Subsumes(const MatchPattern& aPattern) const
443 : {
444 0 : for (auto& scheme : *aPattern.mSchemes) {
445 0 : if (!mSchemes->Contains(scheme)) {
446 0 : return false;
447 : }
448 : }
449 :
450 0 : return SubsumesDomain(aPattern);
451 : }
452 :
453 : bool
454 0 : MatchPattern::Overlaps(const MatchPattern& aPattern) const
455 : {
456 0 : if (!mSchemes->Intersects(*aPattern.mSchemes)) {
457 0 : return false;
458 : }
459 :
460 0 : return SubsumesDomain(aPattern) || aPattern.SubsumesDomain(*this);
461 : }
462 :
463 :
464 : JSObject*
465 0 : MatchPattern::WrapObject(JSContext* aCx, JS::HandleObject aGivenProto)
466 : {
467 0 : return MatchPatternBinding::Wrap(aCx, this, aGivenProto);
468 : }
469 :
470 :
471 0 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MatchPattern, mPath, mParent)
472 :
473 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MatchPattern)
474 0 : NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
475 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
476 0 : NS_INTERFACE_MAP_END
477 :
478 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(MatchPattern)
479 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(MatchPattern)
480 :
481 :
482 : /*****************************************************************************
483 : * MatchPatternSet
484 : *****************************************************************************/
485 :
486 : /* static */ already_AddRefed<MatchPatternSet>
487 0 : MatchPatternSet::Constructor(dom::GlobalObject& aGlobal,
488 : const nsTArray<dom::OwningStringOrMatchPattern>& aPatterns,
489 : const MatchPatternOptions& aOptions,
490 : ErrorResult& aRv)
491 : {
492 0 : ArrayType patterns;
493 :
494 0 : for (auto& elem : aPatterns) {
495 0 : if (elem.IsMatchPattern()) {
496 0 : patterns.AppendElement(elem.GetAsMatchPattern());
497 : } else {
498 0 : RefPtr<MatchPattern> pattern = MatchPattern::Constructor(
499 0 : aGlobal, elem.GetAsString(), aOptions, aRv);
500 :
501 0 : if (!pattern) {
502 0 : return nullptr;
503 : }
504 0 : patterns.AppendElement(Move(pattern));
505 : }
506 : }
507 :
508 0 : RefPtr<MatchPatternSet> patternSet = new MatchPatternSet(aGlobal.GetAsSupports(),
509 0 : Move(patterns));
510 0 : return patternSet.forget();
511 : }
512 :
513 :
514 : bool
515 0 : MatchPatternSet::Matches(const URLInfo& aURL, bool aExplicit) const
516 : {
517 0 : for (const auto& pattern : mPatterns) {
518 0 : if (pattern->Matches(aURL, aExplicit)) {
519 0 : return true;
520 : }
521 : }
522 0 : return false;
523 : }
524 :
525 : bool
526 0 : MatchPatternSet::MatchesCookie(const CookieInfo& aCookie) const
527 : {
528 0 : for (const auto& pattern : mPatterns) {
529 0 : if (pattern->MatchesCookie(aCookie)) {
530 0 : return true;
531 : }
532 : }
533 0 : return false;
534 : }
535 :
536 : bool
537 0 : MatchPatternSet::Subsumes(const MatchPattern& aPattern) const
538 : {
539 0 : for (const auto& pattern : mPatterns) {
540 0 : if (pattern->Subsumes(aPattern)) {
541 0 : return true;
542 : }
543 : }
544 0 : return false;
545 : }
546 :
547 : bool
548 0 : MatchPatternSet::Overlaps(const MatchPatternSet& aPatternSet) const
549 : {
550 0 : for (const auto& pattern : aPatternSet.mPatterns) {
551 0 : if (Overlaps(*pattern)) {
552 0 : return true;
553 : }
554 : }
555 0 : return false;
556 : }
557 :
558 : bool
559 0 : MatchPatternSet::Overlaps(const MatchPattern& aPattern) const
560 : {
561 0 : for (const auto& pattern : mPatterns) {
562 0 : if (pattern->Overlaps(aPattern)) {
563 0 : return true;
564 : }
565 : }
566 0 : return false;
567 : }
568 :
569 :
570 : bool
571 0 : MatchPatternSet::OverlapsAll(const MatchPatternSet& aPatternSet) const
572 : {
573 0 : for (const auto& pattern : aPatternSet.mPatterns) {
574 0 : if (!Overlaps(*pattern)) {
575 0 : return false;
576 : }
577 : }
578 0 : return aPatternSet.mPatterns.Length() > 0;
579 : }
580 :
581 :
582 : JSObject*
583 0 : MatchPatternSet::WrapObject(JSContext* aCx, JS::HandleObject aGivenProto)
584 : {
585 0 : return MatchPatternSetBinding::Wrap(aCx, this, aGivenProto);
586 : }
587 :
588 :
589 0 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MatchPatternSet, mPatterns, mParent)
590 :
591 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MatchPatternSet)
592 0 : NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
593 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
594 0 : NS_INTERFACE_MAP_END
595 :
596 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(MatchPatternSet)
597 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(MatchPatternSet)
598 :
599 :
600 : /*****************************************************************************
601 : * MatchGlob
602 : *****************************************************************************/
603 :
604 0 : MatchGlob::~MatchGlob()
605 : {
606 0 : mozilla::DropJSObjects(this);
607 0 : }
608 :
609 : /* static */ already_AddRefed<MatchGlob>
610 0 : MatchGlob::Constructor(dom::GlobalObject& aGlobal,
611 : const nsAString& aGlob,
612 : bool aAllowQuestion,
613 : ErrorResult& aRv)
614 : {
615 0 : RefPtr<MatchGlob> glob = new MatchGlob(aGlobal.GetAsSupports());
616 0 : glob->Init(aGlobal.Context(), aGlob, aAllowQuestion, aRv);
617 0 : if (aRv.Failed()) {
618 0 : return nullptr;
619 : }
620 0 : return glob.forget();
621 : }
622 :
623 : void
624 0 : MatchGlob::Init(JSContext* aCx, const nsAString& aGlob, bool aAllowQuestion, ErrorResult& aRv)
625 : {
626 0 : mGlob = aGlob;
627 :
628 : // Check for a literal match with no glob metacharacters.
629 0 : auto index = mGlob.FindCharInSet(aAllowQuestion ? "*?" : "*");
630 0 : if (index < 0) {
631 0 : mPathLiteral = mGlob;
632 0 : return;
633 : }
634 :
635 : // Check for a prefix match, where the only glob metacharacter is a "*"
636 : // at the end of the string.
637 0 : if (index == (int32_t)mGlob.Length() - 1 && mGlob[index] == '*') {
638 0 : mPathLiteral = StringHead(mGlob, index);
639 0 : mIsPrefix = true;
640 0 : return;
641 : }
642 :
643 : // Fall back to the regexp slow path.
644 0 : NS_NAMED_LITERAL_CSTRING(metaChars, ".+*?^${}()|[]\\");
645 :
646 0 : nsAutoString escaped;
647 0 : escaped.Append('^');
648 :
649 0 : for (uint32_t i = 0; i < mGlob.Length(); i++) {
650 0 : auto c = mGlob[i];
651 0 : if (c == '*') {
652 0 : escaped.AppendLiteral(".*");
653 0 : } else if (c == '?' && aAllowQuestion) {
654 0 : escaped.Append('.');
655 : } else {
656 0 : if (metaChars.Contains(c)) {
657 0 : escaped.Append('\\');
658 : }
659 0 : escaped.Append(c);
660 : }
661 : }
662 :
663 0 : escaped.Append('$');
664 :
665 : // TODO: Switch to the Rust regexp crate, when Rust integration is easier.
666 : // It uses a much more efficient, linear time matching algorithm, and
667 : // doesn't require special casing for the literal and prefix cases.
668 0 : mRegExp = JS_NewUCRegExpObject(aCx, escaped.get(), escaped.Length(), 0);
669 0 : if (mRegExp) {
670 0 : mozilla::HoldJSObjects(this);
671 : } else {
672 0 : aRv.NoteJSContextException(aCx);
673 : }
674 : }
675 :
676 : bool
677 0 : MatchGlob::Matches(const nsAString& aString) const
678 : {
679 0 : if (mRegExp) {
680 0 : AutoJSAPI jsapi;
681 0 : jsapi.Init();
682 0 : JSContext* cx = jsapi.cx();
683 :
684 0 : JSAutoCompartment ac(cx, mRegExp);
685 :
686 0 : JS::RootedObject regexp(cx, mRegExp);
687 0 : JS::RootedValue result(cx);
688 :
689 0 : nsString input(aString);
690 :
691 0 : size_t index = 0;
692 0 : if (!JS_ExecuteRegExpNoStatics(cx, regexp, input.BeginWriting(), aString.Length(),
693 : &index, true, &result)) {
694 0 : return false;
695 : }
696 :
697 0 : return result.isBoolean() && result.toBoolean();
698 : }
699 :
700 0 : if (mIsPrefix) {
701 0 : return mPathLiteral == StringHead(aString, mPathLiteral.Length());
702 : }
703 :
704 0 : return mPathLiteral == aString;
705 : }
706 :
707 :
708 : JSObject*
709 0 : MatchGlob::WrapObject(JSContext* aCx, JS::HandleObject aGivenProto)
710 : {
711 0 : return MatchGlobBinding::Wrap(aCx, this, aGivenProto);
712 : }
713 :
714 :
715 : NS_IMPL_CYCLE_COLLECTION_CLASS(MatchGlob)
716 :
717 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(MatchGlob)
718 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
719 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
720 0 : tmp->mRegExp = nullptr;
721 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
722 :
723 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(MatchGlob)
724 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
725 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
726 :
727 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(MatchGlob)
728 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
729 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mRegExp)
730 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
731 :
732 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MatchGlob)
733 0 : NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
734 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
735 0 : NS_INTERFACE_MAP_END
736 :
737 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(MatchGlob)
738 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(MatchGlob)
739 :
740 :
741 : /*****************************************************************************
742 : * MatchGlobSet
743 : *****************************************************************************/
744 :
745 : bool
746 0 : MatchGlobSet::Matches(const nsAString& aValue) const
747 : {
748 0 : for (auto& glob : *this) {
749 0 : if (glob->Matches(aValue)) {
750 0 : return true;
751 : }
752 : }
753 0 : return false;
754 : }
755 :
756 : } // namespace extensions
757 : } // namespace mozilla
758 :
|