зеркало из https://github.com/mozilla/gecko-dev.git
759 строки
18 KiB
C++
759 строки
18 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "mozilla/extensions/MatchPattern.h"
|
|
#include "mozilla/extensions/MatchGlob.h"
|
|
|
|
#include "mozilla/dom/ScriptSettings.h"
|
|
#include "mozilla/HoldDropJSObjects.h"
|
|
#include "mozilla/Unused.h"
|
|
|
|
#include "nsGkAtoms.h"
|
|
#include "nsIProtocolHandler.h"
|
|
#include "nsIURL.h"
|
|
#include "nsNetUtil.h"
|
|
|
|
namespace mozilla {
|
|
namespace extensions {
|
|
|
|
using namespace mozilla::dom;
|
|
|
|
|
|
/*****************************************************************************
|
|
* AtomSet
|
|
*****************************************************************************/
|
|
|
|
AtomSet::AtomSet(const nsTArray<nsString>& aElems)
|
|
{
|
|
mElems.SetCapacity(aElems.Length());
|
|
|
|
for (const auto& elem : aElems) {
|
|
mElems.AppendElement(NS_AtomizeMainThread(elem));
|
|
}
|
|
|
|
SortAndUniquify();
|
|
}
|
|
|
|
AtomSet::AtomSet(const char** aElems)
|
|
{
|
|
for (const char** elemp = aElems; *elemp; elemp++) {
|
|
mElems.AppendElement(NS_Atomize(*elemp));
|
|
}
|
|
|
|
SortAndUniquify();
|
|
}
|
|
|
|
AtomSet::AtomSet(std::initializer_list<nsIAtom*> aIL)
|
|
{
|
|
mElems.SetCapacity(aIL.size());
|
|
|
|
for (const auto& elem : aIL) {
|
|
mElems.AppendElement(elem);
|
|
}
|
|
|
|
SortAndUniquify();
|
|
}
|
|
|
|
void
|
|
AtomSet::SortAndUniquify()
|
|
{
|
|
mElems.Sort();
|
|
|
|
nsIAtom* prev = nullptr;
|
|
mElems.RemoveElementsBy([&prev] (const RefPtr<nsIAtom>& aAtom) {
|
|
bool remove = aAtom == prev;
|
|
prev = aAtom;
|
|
return remove;
|
|
});
|
|
|
|
mElems.Compact();
|
|
}
|
|
|
|
bool
|
|
AtomSet::Intersects(const AtomSet& aOther) const
|
|
{
|
|
for (const auto& atom : *this) {
|
|
if (aOther.Contains(atom)) {
|
|
return true;
|
|
}
|
|
}
|
|
for (const auto& atom : aOther) {
|
|
if (Contains(atom)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void
|
|
AtomSet::Add(nsIAtom* aAtom)
|
|
{
|
|
auto index = mElems.IndexOfFirstElementGt(aAtom);
|
|
if (index == 0 || mElems[index - 1] != aAtom) {
|
|
mElems.InsertElementAt(index, aAtom);
|
|
}
|
|
}
|
|
|
|
void
|
|
AtomSet::Remove(nsIAtom* aAtom)
|
|
{
|
|
auto index = mElems.BinaryIndexOf(aAtom);
|
|
if (index != mElems.NoIndex) {
|
|
mElems.RemoveElementAt(index);
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
* URLInfo
|
|
*****************************************************************************/
|
|
|
|
nsIAtom*
|
|
URLInfo::Scheme() const
|
|
{
|
|
if (!mScheme) {
|
|
nsCString scheme;
|
|
if (NS_SUCCEEDED(mURI->GetScheme(scheme))) {
|
|
mScheme = NS_AtomizeMainThread(NS_ConvertASCIItoUTF16(scheme));
|
|
}
|
|
}
|
|
return mScheme;
|
|
}
|
|
|
|
const nsCString&
|
|
URLInfo::Host() const
|
|
{
|
|
if (mHost.IsVoid()) {
|
|
Unused << mURI->GetHost(mHost);
|
|
}
|
|
return mHost;
|
|
}
|
|
|
|
const nsString&
|
|
URLInfo::FilePath() const
|
|
{
|
|
if (mFilePath.IsEmpty()) {
|
|
nsCString path;
|
|
nsCOMPtr<nsIURL> url = do_QueryInterface(mURI);
|
|
if (url && NS_SUCCEEDED(url->GetFilePath(path))) {
|
|
AppendUTF8toUTF16(path, mFilePath);
|
|
} else {
|
|
mFilePath = Path();
|
|
}
|
|
}
|
|
return mFilePath;
|
|
}
|
|
|
|
const nsString&
|
|
URLInfo::Path() const
|
|
{
|
|
if (mPath.IsEmpty()) {
|
|
nsCString path;
|
|
if (NS_SUCCEEDED(URINoRef()->GetPath(path))) {
|
|
AppendUTF8toUTF16(path, mPath);
|
|
}
|
|
}
|
|
return mPath;
|
|
}
|
|
|
|
const nsString&
|
|
URLInfo::Spec() const
|
|
{
|
|
if (mSpec.IsEmpty()) {
|
|
nsCString spec;
|
|
if (NS_SUCCEEDED(URINoRef()->GetSpec(spec))) {
|
|
AppendUTF8toUTF16(spec, mSpec);
|
|
}
|
|
}
|
|
return mSpec;
|
|
}
|
|
|
|
nsIURI*
|
|
URLInfo::URINoRef() const
|
|
{
|
|
if (!mURINoRef) {
|
|
if (NS_FAILED(mURI->CloneIgnoringRef(getter_AddRefs(mURINoRef)))) {
|
|
mURINoRef = mURI;
|
|
}
|
|
}
|
|
return mURINoRef;
|
|
}
|
|
|
|
bool
|
|
URLInfo::InheritsPrincipal() const
|
|
{
|
|
if (!mInheritsPrincipal.isSome()) {
|
|
// For our purposes, about:blank and about:srcdoc are treated as URIs that
|
|
// inherit principals.
|
|
bool inherits = Spec().EqualsLiteral("about:blank") || Spec().EqualsLiteral("about:srcdoc");
|
|
|
|
if (!inherits) {
|
|
nsresult rv = NS_URIChainHasFlags(mURI, nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
|
|
&inherits);
|
|
Unused << NS_WARN_IF(NS_FAILED(rv));
|
|
}
|
|
|
|
mInheritsPrincipal.emplace(inherits);
|
|
}
|
|
return mInheritsPrincipal.ref();
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
* CookieInfo
|
|
*****************************************************************************/
|
|
|
|
bool
|
|
CookieInfo::IsDomain() const
|
|
{
|
|
if (mIsDomain.isNothing()) {
|
|
mIsDomain.emplace(false);
|
|
MOZ_ALWAYS_SUCCEEDS(mCookie->GetIsDomain(mIsDomain.ptr()));
|
|
}
|
|
return mIsDomain.ref();
|
|
}
|
|
|
|
bool
|
|
CookieInfo::IsSecure() const
|
|
{
|
|
if (mIsSecure.isNothing()) {
|
|
mIsSecure.emplace(false);
|
|
MOZ_ALWAYS_SUCCEEDS(mCookie->GetIsSecure(mIsSecure.ptr()));
|
|
}
|
|
return mIsSecure.ref();
|
|
}
|
|
|
|
const nsCString&
|
|
CookieInfo::Host() const
|
|
{
|
|
if (mHost.IsEmpty()) {
|
|
MOZ_ALWAYS_SUCCEEDS(mCookie->GetHost(mHost));
|
|
}
|
|
return mHost;
|
|
}
|
|
|
|
const nsCString&
|
|
CookieInfo::RawHost() const
|
|
{
|
|
if (mRawHost.IsEmpty()) {
|
|
MOZ_ALWAYS_SUCCEEDS(mCookie->GetRawHost(mRawHost));
|
|
}
|
|
return mRawHost;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
* MatchPattern
|
|
*****************************************************************************/
|
|
|
|
const char* PERMITTED_SCHEMES[] = {"http", "https", "ws", "wss", "file", "ftp", "data", nullptr};
|
|
|
|
const char* WILDCARD_SCHEMES[] = {"http", "https", "ws", "wss", nullptr};
|
|
|
|
/* static */ already_AddRefed<MatchPattern>
|
|
MatchPattern::Constructor(dom::GlobalObject& aGlobal,
|
|
const nsAString& aPattern,
|
|
const MatchPatternOptions& aOptions,
|
|
ErrorResult& aRv)
|
|
{
|
|
RefPtr<MatchPattern> pattern = new MatchPattern(aGlobal.GetAsSupports());
|
|
pattern->Init(aGlobal.Context(), aPattern, aOptions.mIgnorePath, aRv);
|
|
if (aRv.Failed()) {
|
|
return nullptr;
|
|
}
|
|
return pattern.forget();
|
|
}
|
|
|
|
void
|
|
MatchPattern::Init(JSContext* aCx, const nsAString& aPattern, bool aIgnorePath, ErrorResult& aRv)
|
|
{
|
|
RefPtr<AtomSet> permittedSchemes = AtomSet::Get<PERMITTED_SCHEMES>();
|
|
|
|
mPattern = aPattern;
|
|
|
|
if (aPattern.EqualsLiteral("<all_urls>")) {
|
|
mSchemes = permittedSchemes;
|
|
mMatchSubdomain = true;
|
|
return;
|
|
}
|
|
|
|
// The portion of the URL we're currently examining.
|
|
uint32_t offset = 0;
|
|
auto tail = Substring(aPattern, offset);
|
|
|
|
/***************************************************************************
|
|
* Scheme
|
|
***************************************************************************/
|
|
int32_t index = aPattern.FindChar(':');
|
|
if (index <= 0) {
|
|
aRv.Throw(NS_ERROR_INVALID_ARG);
|
|
return;
|
|
}
|
|
|
|
nsCOMPtr<nsIAtom> scheme = NS_AtomizeMainThread(StringHead(aPattern, index));
|
|
if (scheme == nsGkAtoms::_asterisk) {
|
|
mSchemes = AtomSet::Get<WILDCARD_SCHEMES>();
|
|
} else if (permittedSchemes->Contains(scheme) || scheme == nsGkAtoms::moz_extension) {
|
|
mSchemes = new AtomSet({scheme});
|
|
} else {
|
|
aRv.Throw(NS_ERROR_INVALID_ARG);
|
|
return;
|
|
}
|
|
|
|
/***************************************************************************
|
|
* Host
|
|
***************************************************************************/
|
|
offset = index + 1;
|
|
tail.Rebind(aPattern, offset);
|
|
|
|
if (!StringHead(tail, 2).EqualsLiteral("//")) {
|
|
aRv.Throw(NS_ERROR_INVALID_ARG);
|
|
return;
|
|
}
|
|
|
|
offset += 2;
|
|
tail.Rebind(aPattern, offset);
|
|
index = tail.FindChar('/');
|
|
if (index < 0) {
|
|
index = tail.Length();
|
|
}
|
|
|
|
auto host = StringHead(tail, index);
|
|
if (host.IsEmpty() && scheme != nsGkAtoms::file) {
|
|
aRv.Throw(NS_ERROR_INVALID_ARG);
|
|
return;
|
|
}
|
|
|
|
offset += index;
|
|
tail.Rebind(aPattern, offset);
|
|
|
|
if (host.EqualsLiteral("*")) {
|
|
mMatchSubdomain = true;
|
|
} else if (StringHead(host, 2).EqualsLiteral("*.")) {
|
|
mDomain = NS_ConvertUTF16toUTF8(Substring(host, 2));
|
|
mMatchSubdomain = true;
|
|
} else {
|
|
mDomain = NS_ConvertUTF16toUTF8(host);
|
|
}
|
|
|
|
/***************************************************************************
|
|
* Path
|
|
***************************************************************************/
|
|
if (aIgnorePath) {
|
|
mPattern.Truncate(offset);
|
|
mPattern.AppendLiteral("/*");
|
|
return;
|
|
}
|
|
|
|
auto path = tail;
|
|
if (path.IsEmpty()) {
|
|
aRv.Throw(NS_ERROR_INVALID_ARG);
|
|
return;
|
|
}
|
|
|
|
mPath = new MatchGlob(this);
|
|
mPath->Init(aCx, path, false, aRv);
|
|
}
|
|
|
|
|
|
bool
|
|
MatchPattern::MatchesDomain(const nsACString& aDomain) const
|
|
{
|
|
if (DomainIsWildcard() || mDomain == aDomain) {
|
|
return true;
|
|
}
|
|
|
|
if (mMatchSubdomain) {
|
|
int64_t offset = (int64_t)aDomain.Length() - mDomain.Length();
|
|
if (offset > 0 && aDomain[offset - 1] == '.' &&
|
|
Substring(aDomain, offset) == mDomain) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
MatchPattern::Matches(const URLInfo& aURL, bool aExplicit) const
|
|
{
|
|
if (aExplicit && mMatchSubdomain) {
|
|
return false;
|
|
}
|
|
|
|
if (!mSchemes->Contains(aURL.Scheme())) {
|
|
return false;
|
|
}
|
|
|
|
if (!DomainIsWildcard() && !MatchesDomain(aURL.Host())) {
|
|
return false;
|
|
}
|
|
|
|
if (mPath && !mPath->IsWildcard() && !mPath->Matches(aURL.Path())) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
MatchPattern::MatchesCookie(const CookieInfo& aCookie) const
|
|
{
|
|
if (!mSchemes->Contains(nsGkAtoms::https) &&
|
|
(aCookie.IsSecure() || !mSchemes->Contains(nsGkAtoms::http))) {
|
|
return false;
|
|
}
|
|
|
|
if (MatchesDomain(aCookie.RawHost())) {
|
|
return true;
|
|
}
|
|
|
|
if (!aCookie.IsDomain()) {
|
|
return false;
|
|
}
|
|
|
|
// Things get tricker for domain cookies. The extension needs to be able
|
|
// to read any cookies that could be read by any host it has permissions
|
|
// for. This means that our normal host matching checks won't work,
|
|
// since the pattern "*://*.foo.example.com/" doesn't match ".example.com",
|
|
// but it does match "bar.foo.example.com", which can read cookies
|
|
// with the domain ".example.com".
|
|
//
|
|
// So, instead, we need to manually check our filters, and accept any
|
|
// with hosts that end with our cookie's host.
|
|
|
|
auto& host = aCookie.Host();
|
|
return StringTail(mDomain, host.Length()) == host;
|
|
}
|
|
|
|
bool
|
|
MatchPattern::SubsumesDomain(const MatchPattern& aPattern) const
|
|
{
|
|
if (!mMatchSubdomain && aPattern.mMatchSubdomain && aPattern.mDomain == mDomain) {
|
|
return false;
|
|
}
|
|
|
|
return MatchesDomain(aPattern.mDomain);
|
|
}
|
|
|
|
bool
|
|
MatchPattern::Subsumes(const MatchPattern& aPattern) const
|
|
{
|
|
for (auto& scheme : *aPattern.mSchemes) {
|
|
if (!mSchemes->Contains(scheme)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return SubsumesDomain(aPattern);
|
|
}
|
|
|
|
bool
|
|
MatchPattern::Overlaps(const MatchPattern& aPattern) const
|
|
{
|
|
if (!mSchemes->Intersects(*aPattern.mSchemes)) {
|
|
return false;
|
|
}
|
|
|
|
return SubsumesDomain(aPattern) || aPattern.SubsumesDomain(*this);
|
|
}
|
|
|
|
|
|
JSObject*
|
|
MatchPattern::WrapObject(JSContext* aCx, JS::HandleObject aGivenProto)
|
|
{
|
|
return MatchPatternBinding::Wrap(aCx, this, aGivenProto);
|
|
}
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MatchPattern, mPath, mParent)
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MatchPattern)
|
|
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
|
NS_INTERFACE_MAP_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(MatchPattern)
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(MatchPattern)
|
|
|
|
|
|
/*****************************************************************************
|
|
* MatchPatternSet
|
|
*****************************************************************************/
|
|
|
|
/* static */ already_AddRefed<MatchPatternSet>
|
|
MatchPatternSet::Constructor(dom::GlobalObject& aGlobal,
|
|
const nsTArray<dom::OwningStringOrMatchPattern>& aPatterns,
|
|
const MatchPatternOptions& aOptions,
|
|
ErrorResult& aRv)
|
|
{
|
|
ArrayType patterns;
|
|
|
|
for (auto& elem : aPatterns) {
|
|
if (elem.IsMatchPattern()) {
|
|
patterns.AppendElement(elem.GetAsMatchPattern());
|
|
} else {
|
|
RefPtr<MatchPattern> pattern = MatchPattern::Constructor(
|
|
aGlobal, elem.GetAsString(), aOptions, aRv);
|
|
|
|
if (!pattern) {
|
|
return nullptr;
|
|
}
|
|
patterns.AppendElement(Move(pattern));
|
|
}
|
|
}
|
|
|
|
RefPtr<MatchPatternSet> patternSet = new MatchPatternSet(aGlobal.GetAsSupports(),
|
|
Move(patterns));
|
|
return patternSet.forget();
|
|
}
|
|
|
|
|
|
bool
|
|
MatchPatternSet::Matches(const URLInfo& aURL, bool aExplicit) const
|
|
{
|
|
for (const auto& pattern : mPatterns) {
|
|
if (pattern->Matches(aURL, aExplicit)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
MatchPatternSet::MatchesCookie(const CookieInfo& aCookie) const
|
|
{
|
|
for (const auto& pattern : mPatterns) {
|
|
if (pattern->MatchesCookie(aCookie)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
MatchPatternSet::Subsumes(const MatchPattern& aPattern) const
|
|
{
|
|
for (const auto& pattern : mPatterns) {
|
|
if (pattern->Subsumes(aPattern)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
MatchPatternSet::Overlaps(const MatchPatternSet& aPatternSet) const
|
|
{
|
|
for (const auto& pattern : aPatternSet.mPatterns) {
|
|
if (Overlaps(*pattern)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
MatchPatternSet::Overlaps(const MatchPattern& aPattern) const
|
|
{
|
|
for (const auto& pattern : mPatterns) {
|
|
if (pattern->Overlaps(aPattern)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
bool
|
|
MatchPatternSet::OverlapsAll(const MatchPatternSet& aPatternSet) const
|
|
{
|
|
for (const auto& pattern : aPatternSet.mPatterns) {
|
|
if (!Overlaps(*pattern)) {
|
|
return false;
|
|
}
|
|
}
|
|
return aPatternSet.mPatterns.Length() > 0;
|
|
}
|
|
|
|
|
|
JSObject*
|
|
MatchPatternSet::WrapObject(JSContext* aCx, JS::HandleObject aGivenProto)
|
|
{
|
|
return MatchPatternSetBinding::Wrap(aCx, this, aGivenProto);
|
|
}
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MatchPatternSet, mPatterns, mParent)
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MatchPatternSet)
|
|
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
|
NS_INTERFACE_MAP_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(MatchPatternSet)
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(MatchPatternSet)
|
|
|
|
|
|
/*****************************************************************************
|
|
* MatchGlob
|
|
*****************************************************************************/
|
|
|
|
MatchGlob::~MatchGlob()
|
|
{
|
|
mozilla::DropJSObjects(this);
|
|
}
|
|
|
|
/* static */ already_AddRefed<MatchGlob>
|
|
MatchGlob::Constructor(dom::GlobalObject& aGlobal,
|
|
const nsAString& aGlob,
|
|
bool aAllowQuestion,
|
|
ErrorResult& aRv)
|
|
{
|
|
RefPtr<MatchGlob> glob = new MatchGlob(aGlobal.GetAsSupports());
|
|
glob->Init(aGlobal.Context(), aGlob, aAllowQuestion, aRv);
|
|
if (aRv.Failed()) {
|
|
return nullptr;
|
|
}
|
|
return glob.forget();
|
|
}
|
|
|
|
void
|
|
MatchGlob::Init(JSContext* aCx, const nsAString& aGlob, bool aAllowQuestion, ErrorResult& aRv)
|
|
{
|
|
mGlob = aGlob;
|
|
|
|
// Check for a literal match with no glob metacharacters.
|
|
auto index = mGlob.FindCharInSet(aAllowQuestion ? "*?" : "*");
|
|
if (index < 0) {
|
|
mPathLiteral = mGlob;
|
|
return;
|
|
}
|
|
|
|
// Check for a prefix match, where the only glob metacharacter is a "*"
|
|
// at the end of the string.
|
|
if (index == (int32_t)mGlob.Length() - 1 && mGlob[index] == '*') {
|
|
mPathLiteral = StringHead(mGlob, index);
|
|
mIsPrefix = true;
|
|
return;
|
|
}
|
|
|
|
// Fall back to the regexp slow path.
|
|
NS_NAMED_LITERAL_CSTRING(metaChars, ".+*?^${}()|[]\\");
|
|
|
|
nsAutoString escaped;
|
|
escaped.Append('^');
|
|
|
|
for (uint32_t i = 0; i < mGlob.Length(); i++) {
|
|
auto c = mGlob[i];
|
|
if (c == '*') {
|
|
escaped.AppendLiteral(".*");
|
|
} else if (c == '?' && aAllowQuestion) {
|
|
escaped.Append('.');
|
|
} else {
|
|
if (metaChars.Contains(c)) {
|
|
escaped.Append('\\');
|
|
}
|
|
escaped.Append(c);
|
|
}
|
|
}
|
|
|
|
escaped.Append('$');
|
|
|
|
// TODO: Switch to the Rust regexp crate, when Rust integration is easier.
|
|
// It uses a much more efficient, linear time matching algorithm, and
|
|
// doesn't require special casing for the literal and prefix cases.
|
|
mRegExp = JS_NewUCRegExpObject(aCx, escaped.get(), escaped.Length(), 0);
|
|
if (mRegExp) {
|
|
mozilla::HoldJSObjects(this);
|
|
} else {
|
|
aRv.NoteJSContextException(aCx);
|
|
}
|
|
}
|
|
|
|
bool
|
|
MatchGlob::Matches(const nsAString& aString) const
|
|
{
|
|
if (mRegExp) {
|
|
AutoJSAPI jsapi;
|
|
jsapi.Init();
|
|
JSContext* cx = jsapi.cx();
|
|
|
|
JSAutoCompartment ac(cx, mRegExp);
|
|
|
|
JS::RootedObject regexp(cx, mRegExp);
|
|
JS::RootedValue result(cx);
|
|
|
|
nsString input(aString);
|
|
|
|
size_t index = 0;
|
|
if (!JS_ExecuteRegExpNoStatics(cx, regexp, input.BeginWriting(), aString.Length(),
|
|
&index, true, &result)) {
|
|
return false;
|
|
}
|
|
|
|
return result.isBoolean() && result.toBoolean();
|
|
}
|
|
|
|
if (mIsPrefix) {
|
|
return mPathLiteral == StringHead(aString, mPathLiteral.Length());
|
|
}
|
|
|
|
return mPathLiteral == aString;
|
|
}
|
|
|
|
|
|
JSObject*
|
|
MatchGlob::WrapObject(JSContext* aCx, JS::HandleObject aGivenProto)
|
|
{
|
|
return MatchGlobBinding::Wrap(aCx, this, aGivenProto);
|
|
}
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(MatchGlob)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(MatchGlob)
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
|
|
tmp->mRegExp = nullptr;
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(MatchGlob)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(MatchGlob)
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mRegExp)
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MatchGlob)
|
|
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
|
NS_INTERFACE_MAP_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(MatchGlob)
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(MatchGlob)
|
|
|
|
|
|
/*****************************************************************************
|
|
* MatchGlobSet
|
|
*****************************************************************************/
|
|
|
|
bool
|
|
MatchGlobSet::Matches(const nsAString& aValue) const
|
|
{
|
|
for (auto& glob : *this) {
|
|
if (glob->Matches(aValue)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
} // namespace extensions
|
|
} // namespace mozilla
|
|
|