LCOV - code coverage report
Current view: top level - toolkit/components/extensions - MatchPattern.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 54 352 15.3 %
Date: 2018-08-07 16:35:00 Functions: 0 0 -
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13-14-ga5dd952