Skip to content

Commit 88a98e8

Browse files
committed
Bug 1484373: Part 6 - Minimize the amount of JS processing required to init extension policies. r=mixedpuppy
Differential Revision: https://phabricator.services.mozilla.com/D3696 --HG-- extra : rebase_source : a0c5b225ba810ccee7fbbbaea06f8eb8d2878cf7 extra : histedit_source : e8bab5d1c67d03d8b9f632802dcf6a24d84b46c3
1 parent c699423 commit 88a98e8

File tree

6 files changed

+138
-62
lines changed

6 files changed

+138
-62
lines changed

dom/chrome-webidl/WebExtensionContentScript.webidl

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ interface LoadInfo;
66
interface URI;
77
interface WindowProxy;
88

9+
typedef (MatchPatternSet or sequence<DOMString>) MatchPatternSetOrStringSequence;
10+
typedef (MatchGlob or DOMString) MatchGlobOrString;
11+
912
[Constructor(MozDocumentMatcherInit options), ChromeOnly, Exposed=System]
1013
interface MozDocumentMatcher {
1114
/**
@@ -94,13 +97,13 @@ dictionary MozDocumentMatcherInit {
9497

9598
unsigned long long? frameID = null;
9699

97-
required MatchPatternSet matches;
100+
required MatchPatternSetOrStringSequence matches;
98101

99-
MatchPatternSet? excludeMatches = null;
102+
MatchPatternSetOrStringSequence? excludeMatches = null;
100103

101-
sequence<MatchGlob>? includeGlobs = null;
104+
sequence<MatchGlobOrString>? includeGlobs = null;
102105

103-
sequence<MatchGlob>? excludeGlobs = null;
106+
sequence<MatchGlobOrString>? excludeGlobs = null;
104107

105108
boolean hasActiveTabPermission = false;
106109
};

dom/chrome-webidl/WebExtensionPolicy.webidl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,11 +182,11 @@ dictionary WebExtensionInit {
182182

183183
required WebExtensionLocalizeCallback localizeCallback;
184184

185-
required MatchPatternSet allowedOrigins;
185+
required MatchPatternSetOrStringSequence allowedOrigins;
186186

187187
sequence<DOMString> permissions = [];
188188

189-
sequence<MatchGlob> webAccessibleResources = [];
189+
sequence<MatchGlobOrString> webAccessibleResources = [];
190190

191191
sequence<WebExtensionContentScriptInit> contentScripts = [];
192192

toolkit/components/extensions/WebExtensionContentScript.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,9 @@ class MozDocumentMatcher : public nsISupports
148148

149149
virtual ~MozDocumentMatcher() = default;
150150

151-
MozDocumentMatcher(const dom::MozDocumentMatcherInit& aInit,
152-
ErrorResult& aRv);
151+
MozDocumentMatcher(dom::GlobalObject& aGlobal,
152+
const dom::MozDocumentMatcherInit& aInit,
153+
bool aRestricted, ErrorResult& aRv);
153154

154155
RefPtr<WebExtensionPolicy> mExtension;
155156

@@ -210,7 +211,8 @@ class WebExtensionContentScript final : public MozDocumentMatcher
210211

211212
virtual ~WebExtensionContentScript() = default;
212213

213-
WebExtensionContentScript(WebExtensionPolicy& aExtension,
214+
WebExtensionContentScript(dom::GlobalObject& aGlobal,
215+
WebExtensionPolicy& aExtension,
214216
const ContentScriptInit& aInit,
215217
ErrorResult& aRv);
216218

toolkit/components/extensions/WebExtensionPolicy.cpp

Lines changed: 113 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,68 @@ Proto()
6767
}
6868

6969

70+
bool
71+
ParseGlobs(GlobalObject& aGlobal, Sequence<OwningMatchGlobOrString> aGlobs,
72+
nsTArray<RefPtr<MatchGlob>>& aResult, ErrorResult& aRv)
73+
{
74+
for (auto& elem : aGlobs) {
75+
if (elem.IsMatchGlob()) {
76+
aResult.AppendElement(elem.GetAsMatchGlob());
77+
} else {
78+
RefPtr<MatchGlob> glob = MatchGlob::Constructor(aGlobal,
79+
elem.GetAsString(),
80+
true, aRv);
81+
if (aRv.Failed()) {
82+
return false;
83+
}
84+
aResult.AppendElement(glob);
85+
}
86+
}
87+
return true;
88+
}
89+
90+
enum class ErrorBehavior {
91+
CreateEmptyPattern,
92+
Fail,
93+
};
94+
95+
already_AddRefed<MatchPatternSet>
96+
ParseMatches(GlobalObject& aGlobal,
97+
const OwningMatchPatternSetOrStringSequence& aMatches,
98+
const MatchPatternOptions& aOptions,
99+
ErrorBehavior aErrorBehavior,
100+
ErrorResult& aRv)
101+
{
102+
if (aMatches.IsMatchPatternSet()) {
103+
return do_AddRef(aMatches.GetAsMatchPatternSet().get());
104+
}
105+
106+
const auto& strings = aMatches.GetAsStringSequence();
107+
108+
nsTArray<OwningStringOrMatchPattern> patterns;
109+
if (!patterns.SetCapacity(strings.Length(), fallible)) {
110+
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
111+
return nullptr;
112+
}
113+
114+
for (auto& string : strings) {
115+
OwningStringOrMatchPattern elt;
116+
elt.SetAsString() = string;
117+
patterns.AppendElement(elt);
118+
}
119+
120+
RefPtr<MatchPatternSet> result = MatchPatternSet::Constructor(
121+
aGlobal, patterns, aOptions, aRv);
122+
123+
if (aRv.Failed() && aErrorBehavior == ErrorBehavior::CreateEmptyPattern) {
124+
aRv.SuppressException();
125+
result = MatchPatternSet::Constructor(aGlobal, {}, aOptions, aRv);
126+
}
127+
128+
return result.forget();
129+
}
130+
131+
70132
/*****************************************************************************
71133
* WebExtensionPolicy
72134
*****************************************************************************/
@@ -80,9 +142,20 @@ WebExtensionPolicy::WebExtensionPolicy(GlobalObject& aGlobal,
80142
, mContentSecurityPolicy(aInit.mContentSecurityPolicy)
81143
, mLocalizeCallback(aInit.mLocalizeCallback)
82144
, mPermissions(new AtomSet(aInit.mPermissions))
83-
, mHostPermissions(aInit.mAllowedOrigins)
84145
{
85-
mWebAccessiblePaths.AppendElements(aInit.mWebAccessibleResources);
146+
if (!ParseGlobs(aGlobal, aInit.mWebAccessibleResources, mWebAccessiblePaths,
147+
aRv)) {
148+
return;
149+
}
150+
151+
MatchPatternOptions options;
152+
options.mRestrictSchemes = HasPermission(nsGkAtoms::mozillaAddons);
153+
154+
mHostPermissions = ParseMatches(aGlobal, aInit.mAllowedOrigins, options,
155+
ErrorBehavior::CreateEmptyPattern, aRv);
156+
if (aRv.Failed()) {
157+
return;
158+
}
86159

87160
if (!aInit.mBackgroundScripts.IsNull()) {
88161
mBackgroundScripts.SetValue().AppendElements(aInit.mBackgroundScripts.Value());
@@ -102,7 +175,7 @@ WebExtensionPolicy::WebExtensionPolicy(GlobalObject& aGlobal,
102175
}
103176

104177
RefPtr<WebExtensionContentScript> contentScript =
105-
new WebExtensionContentScript(*this, scriptInit, aRv);
178+
new WebExtensionContentScript(aGlobal, *this, scriptInit, aRv);
106179
if (aRv.Failed()) {
107180
return;
108181
}
@@ -446,7 +519,8 @@ MozDocumentMatcher::Constructor(GlobalObject& aGlobal,
446519
const dom::MozDocumentMatcherInit& aInit,
447520
ErrorResult& aRv)
448521
{
449-
RefPtr<MozDocumentMatcher> matcher = new MozDocumentMatcher(aInit, aRv);
522+
RefPtr<MozDocumentMatcher> matcher = new MozDocumentMatcher(aGlobal, aInit,
523+
false, aRv);
450524
if (aRv.Failed()) {
451525
return nullptr;
452526
}
@@ -459,42 +533,67 @@ WebExtensionContentScript::Constructor(GlobalObject& aGlobal,
459533
const ContentScriptInit& aInit,
460534
ErrorResult& aRv)
461535
{
462-
RefPtr<WebExtensionContentScript> script = new WebExtensionContentScript(aExtension, aInit, aRv);
536+
RefPtr<WebExtensionContentScript> script = new WebExtensionContentScript(
537+
aGlobal, aExtension, aInit, aRv);
463538
if (aRv.Failed()) {
464539
return nullptr;
465540
}
466541
return script.forget();
467542
}
468543

469-
MozDocumentMatcher::MozDocumentMatcher(const dom::MozDocumentMatcherInit& aInit,
544+
MozDocumentMatcher::MozDocumentMatcher(GlobalObject& aGlobal,
545+
const dom::MozDocumentMatcherInit& aInit,
546+
bool aRestricted,
470547
ErrorResult& aRv)
471548
: mHasActiveTabPermission(aInit.mHasActiveTabPermission)
472-
, mRestricted(false)
473-
, mMatches(aInit.mMatches)
474-
, mExcludeMatches(aInit.mExcludeMatches)
549+
, mRestricted(aRestricted)
475550
, mAllFrames(aInit.mAllFrames)
476551
, mFrameID(aInit.mFrameID)
477552
, mMatchAboutBlank(aInit.mMatchAboutBlank)
478553
{
554+
MatchPatternOptions options;
555+
options.mRestrictSchemes = mRestricted;
556+
557+
mMatches = ParseMatches(aGlobal, aInit.mMatches, options,
558+
ErrorBehavior::CreateEmptyPattern, aRv);
559+
if (aRv.Failed()) {
560+
return;
561+
}
562+
563+
if (!aInit.mExcludeMatches.IsNull()) {
564+
mExcludeMatches = ParseMatches(aGlobal, aInit.mExcludeMatches.Value(),
565+
options, ErrorBehavior::CreateEmptyPattern,
566+
aRv);
567+
if (aRv.Failed()) {
568+
return;
569+
}
570+
}
571+
479572
if (!aInit.mIncludeGlobs.IsNull()) {
480-
mIncludeGlobs.SetValue().AppendElements(aInit.mIncludeGlobs.Value());
573+
if (!ParseGlobs(aGlobal, aInit.mIncludeGlobs.Value(), mIncludeGlobs.SetValue(),
574+
aRv)) {
575+
return;
576+
}
481577
}
482578

483579
if (!aInit.mExcludeGlobs.IsNull()) {
484-
mExcludeGlobs.SetValue().AppendElements(aInit.mExcludeGlobs.Value());
580+
if (!ParseGlobs(aGlobal, aInit.mExcludeGlobs.Value(), mExcludeGlobs.SetValue(),
581+
aRv)) {
582+
return;
583+
}
485584
}
486585
}
487586

488-
WebExtensionContentScript::WebExtensionContentScript(WebExtensionPolicy& aExtension,
587+
WebExtensionContentScript::WebExtensionContentScript(GlobalObject& aGlobal,
588+
WebExtensionPolicy& aExtension,
489589
const ContentScriptInit& aInit,
490590
ErrorResult& aRv)
491-
: MozDocumentMatcher(aInit, aRv)
591+
: MozDocumentMatcher(aGlobal, aInit, !aExtension.HasPermission(nsGkAtoms::mozillaAddons), aRv)
492592
, mCssPaths(aInit.mCssPaths)
493593
, mJsPaths(aInit.mJsPaths)
494594
, mRunAt(aInit.mRunAt)
495595
{
496596
mExtension = &aExtension;
497-
mRestricted = !aExtension.HasPermission(nsGkAtoms::mozillaAddons);
498597
}
499598

500599
bool

toolkit/components/extensions/extension-process-script.js

Lines changed: 8 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -42,26 +42,6 @@ function getData(extension, key = "") {
4242
const appinfo = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime);
4343
const isContentProcess = appinfo.processType == appinfo.PROCESS_TYPE_CONTENT;
4444

45-
function tryMatchPatternSet(patterns, options) {
46-
try {
47-
return new MatchPatternSet(patterns, options);
48-
} catch (e) {
49-
Cu.reportError(e);
50-
return new MatchPatternSet([]);
51-
}
52-
}
53-
54-
function parseScriptOptions(options, restrictSchemes = true) {
55-
return {
56-
...options,
57-
58-
matches: tryMatchPatternSet(options.matches, {restrictSchemes}),
59-
excludeMatches: tryMatchPatternSet(options.excludeMatches || [], {restrictSchemes}),
60-
includeGlobs: options.includeGlobs && options.includeGlobs.map(glob => new MatchGlob(glob)),
61-
excludeGlobs: options.excludeGlobs && options.excludeGlobs.map(glob => new MatchGlob(glob)),
62-
};
63-
}
64-
6545
var extensions = new DefaultWeakMap(policy => {
6646
let data = policy.initData;
6747
if (data.serialize) {
@@ -133,7 +113,7 @@ class ExtensionGlobal {
133113
case "Extension:Execute":
134114
let policy = WebExtensionPolicy.getByID(recipient.extensionId);
135115

136-
let matcher = new WebExtensionContentScript(policy, parseScriptOptions(data.options, !policy.hasPermission("mozillaAddons")));
116+
let matcher = new WebExtensionContentScript(policy, data.options);
137117

138118
Object.assign(matcher, {
139119
wantReturnValue: data.options.wantReturnValue,
@@ -250,19 +230,13 @@ ExtensionManager = {
250230
initExtensionPolicy(extension) {
251231
let policy = WebExtensionPolicy.getByID(extension.id);
252232
if (!policy) {
253-
let localizeCallback, allowedOrigins, webAccessibleResources;
254-
let restrictSchemes = !extension.permissions.has("mozillaAddons");
255-
233+
let localizeCallback;
256234
if (extension.localize) {
257235
// We have a real Extension object.
258236
localizeCallback = extension.localize.bind(extension);
259-
allowedOrigins = extension.whiteListedHosts;
260-
webAccessibleResources = extension.webAccessibleResources;
261237
} else {
262238
// We have serialized extension data;
263239
localizeCallback = str => extensions.get(policy).localize(str);
264-
allowedOrigins = new MatchPatternSet(extension.whiteListedHosts, {restrictSchemes});
265-
webAccessibleResources = extension.webAccessibleResources.map(host => new MatchGlob(host));
266240
}
267241

268242
let {backgroundScripts} = extension;
@@ -276,17 +250,17 @@ ExtensionManager = {
276250
name: extension.name,
277251
baseURL: extension.resourceURL,
278252

279-
permissions: Array.from(extension.permissions),
280-
allowedOrigins,
281-
webAccessibleResources,
253+
permissions: extension.permissions,
254+
allowedOrigins: extension.whiteListedHosts,
255+
webAccessibleResources: extension.webAccessibleResources,
282256

283257
contentSecurityPolicy: extension.contentSecurityPolicy,
284258

285259
localizeCallback,
286260

287261
backgroundScripts,
288262

289-
contentScripts: extension.contentScripts.map(script => parseScriptOptions(script, restrictSchemes)),
263+
contentScripts: extension.contentScripts,
290264
});
291265

292266
policy.debugName = `${JSON.stringify(policy.name)} (ID: ${policy.id}, ${policy.getURL()})`;
@@ -297,8 +271,7 @@ ExtensionManager = {
297271
const registeredContentScripts = this.registeredContentScripts.get(policy);
298272

299273
for (let [scriptId, options] of getData(extension, "contentScripts") || []) {
300-
const parsedOptions = parseScriptOptions(options, restrictSchemes);
301-
const script = new WebExtensionContentScript(policy, parsedOptions);
274+
const script = new WebExtensionContentScript(policy, options);
302275
policy.registerContentScript(script);
303276
registeredContentScripts.set(scriptId, script);
304277
}
@@ -360,8 +333,7 @@ ExtensionManager = {
360333
`Registering content script ${data.scriptId} on ${data.id} more than once`));
361334
} else {
362335
try {
363-
const parsedOptions = parseScriptOptions(data.options, !policy.hasPermission("mozillaAddons"));
364-
const script = new WebExtensionContentScript(policy, parsedOptions);
336+
const script = new WebExtensionContentScript(policy, data.options);
365337
policy.registerContentScript(script);
366338
registeredContentScripts.set(data.scriptId, script);
367339
} catch (e) {

toolkit/components/extensions/parent/ext-tabs-base.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -673,7 +673,7 @@ class TabBase {
673673
if (!this.extension.isExtensionURL(url)) {
674674
return Promise.reject({message: "Files to be injected must be within the extension"});
675675
}
676-
options[kind].push(url);
676+
options[`${kind}Paths`].push(url);
677677
}
678678
if (details.allFrames) {
679679
options.allFrames = details.allFrames;
@@ -717,7 +717,7 @@ class TabBase {
717717
* generates.
718718
*/
719719
executeScript(context, details) {
720-
return this._execute(context, details, "jsPaths", "executeScript");
720+
return this._execute(context, details, "js", "executeScript");
721721
}
722722

723723
/**
@@ -733,7 +733,7 @@ class TabBase {
733733
* Resolves when the injection has completed.
734734
*/
735735
insertCSS(context, details) {
736-
return this._execute(context, details, "cssPaths", "insertCSS").then(() => {});
736+
return this._execute(context, details, "css", "insertCSS").then(() => {});
737737
}
738738

739739

0 commit comments

Comments
 (0)