Merge mozilla-central to autoland. a=merge CLOSED TREE

This commit is contained in:
Margareta Eliza Balazs 2018-05-16 13:06:18 +03:00
commit e5bdfc5b27
64 changed files with 731 additions and 484 deletions

View File

@ -719,8 +719,6 @@ pref("plugin.default.state", 1);
// Plugins bundled in XPIs are enabled by default.
pref("plugin.defaultXpi.state", 2);
// Java is Click-to-Activate by default on all channels.
pref("plugin.state.java", 1);
// Flash is Click-to-Activate by default on all channels.
pref("plugin.state.flash", 1);

View File

@ -1,6 +1,6 @@
const PREF_MULTISELECT_TABS = "browser.tabs.multiselect";
async function triggerClickOn(target, options) {
function triggerClickOn(target, options) {
let promise = BrowserTestUtils.waitForEvent(target, "click");
if (AppConstants.platform == "macosx") {
options = { metaKey: options.ctrlKey };
@ -10,7 +10,7 @@ async function triggerClickOn(target, options) {
}
async function addTab() {
const tab = BrowserTestUtils.addTab(gBrowser, "http://mochi.test:8888/");
const tab = BrowserTestUtils.addTab(gBrowser, "http://mochi.test:8888/", {skipAnimation: true});
const browser = gBrowser.getBrowserForTab(tab);
await BrowserTestUtils.browserLoaded(browser);
return tab;
@ -22,7 +22,13 @@ add_task(async function clickWithoutPrefSet() {
isnot(gBrowser.selectedTab, tab, "Tab doesn't have focus");
await triggerClickOn(tab, { ctrlKey: true });
// We make sure that the tab-switch is completely done before executing checks
await BrowserTestUtils.switchTab(gBrowser, () => {
triggerClickOn(tab, { ctrlKey: true });
});
await TestUtils.waitForCondition(() => gBrowser.selectedTab == tab,
"Wait for the selectedTab getter to update");
ok(!tab.multiselected && !mSelectedTabs.has(tab),
"Multi-select tab doesn't work when multi-select pref is not set");

View File

@ -1843,7 +1843,7 @@ BrowserGlue.prototype = {
_migrateUI: function BG__migrateUI() {
// Use an increasing number to keep track of the current migration state.
// Completely unrelated to the current Firefox release number.
const UI_VERSION = 68;
const UI_VERSION = 69;
const BROWSER_DOCURL = "chrome://browser/content/browser.xul";
let currentUIVersion;
@ -2205,6 +2205,17 @@ BrowserGlue.prototype = {
"kinto.sqlite"), {ignoreAbsent: true});
}
if (currentUIVersion < 69) {
// Clear old social prefs from profile (bug 1460675)
let socialPrefs = Services.prefs.getBranch("social.");
if (socialPrefs) {
let socialPrefsArray = socialPrefs.getChildList("");
for (let item of socialPrefsArray) {
Services.prefs.clearUserPref("social." + item);
}
}
}
// Update the migration version.
Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
},

View File

@ -0,0 +1,23 @@
const UI_VERSION = 69;
const TOPIC_BROWSERGLUE_TEST = "browser-glue-test";
const TOPICDATA_BROWSERGLUE_TEST = "force-ui-migration";
var gBrowserGlue = Cc["@mozilla.org/browser/browserglue;1"]
.getService(Ci.nsIObserver);
Services.prefs.setIntPref("browser.migration.version", UI_VERSION - 1);
add_task(async function test_check_cleanup_social_prefs() {
Services.prefs.setStringPref("social.manifest.example-com", "example.com");
// Simulate a migration.
gBrowserGlue.observe(null, TOPIC_BROWSERGLUE_TEST, TOPICDATA_BROWSERGLUE_TEST);
Assert.ok(!Services.prefs.prefHasUserValue("social.manifest.example-com"),
"should have cleared old social preference 'social.manifest.example-com'");
});
registerCleanupFunction(() => {
Services.prefs.clearUserPref("browser.migration.version");
Services.prefs.clearUserPref("social.manifest.example-com");
});

View File

@ -9,4 +9,5 @@ support-files =
[test_browserGlue_migration_loop_cleanup.js]
[test_distribution.js]
[test_distribution_cachedexistence.js]
[test_browserGlue_migration_social_cleanup.js]
[test_browserGlue_pingcentre.js]

View File

@ -615,31 +615,6 @@ Navigator::GetDoNotTrack(nsAString &aResult)
}
}
bool
Navigator::JavaEnabled(CallerType aCallerType, ErrorResult& aRv)
{
Telemetry::AutoTimer<Telemetry::CHECK_JAVA_ENABLED> telemetryTimer;
// Return true if we have a handler for the java mime
nsAutoString javaMIME;
Preferences::GetString("plugin.java.mime", javaMIME);
NS_ENSURE_TRUE(!javaMIME.IsEmpty(), false);
if (!mMimeTypes) {
if (!mWindow) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return false;
}
mMimeTypes = new nsMimeTypeArray(mWindow);
}
RefreshMIMEArray();
nsMimeType *mimeType = mMimeTypes->NamedItem(javaMIME, aCallerType);
return mimeType && mimeType->GetEnabledPlugin();
}
uint64_t
Navigator::HardwareConcurrency()
{

View File

@ -158,7 +158,10 @@ public:
bool CookieEnabled();
void GetBuildID(nsAString& aBuildID, CallerType aCallerType,
ErrorResult& aRv) const;
bool JavaEnabled(CallerType aCallerType, ErrorResult& aRv);
bool JavaEnabled()
{
return false;
}
uint64_t HardwareConcurrency();
bool TaintEnabled()
{

View File

@ -42,7 +42,10 @@ public:
StructuredCloneHolderBase(StructuredCloneScope aScope = StructuredCloneScope::SameProcessSameThread);
virtual ~StructuredCloneHolderBase();
StructuredCloneHolderBase(StructuredCloneHolderBase&& aOther) = default;
// Note, it is unsafe to Move() a StructuredCloneHolderBase since a raw
// this pointer is passed to mBuffer as a callback closure. That must
// be fixed if you want to implement a move constructor here.
StructuredCloneHolderBase(StructuredCloneHolderBase&& aOther) = delete;
// These methods should be implemented in order to clone data.
// Read more documentation in js/public/StructuredClone.h.
@ -173,7 +176,7 @@ public:
StructuredCloneScope aStructuredCloneScope);
virtual ~StructuredCloneHolder();
StructuredCloneHolder(StructuredCloneHolder&& aOther) = default;
StructuredCloneHolder(StructuredCloneHolder&& aOther) = delete;
// Normally you should just use Write() and Read().

View File

@ -46,3 +46,4 @@ DEPRECATED_OPERATION(OrientationEvent)
DEPRECATED_OPERATION(ProximityEvent)
DEPRECATED_OPERATION(AmbientLightEvent)
DEPRECATED_OPERATION(IDBOpenDBOptions_StorageType)
DEPRECATED_OPERATION(DOMAttrModifiedEvent)

View File

@ -326,6 +326,9 @@ EventListenerManager::AddEventListenerInternal(
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
if (doc) {
doc->WarnOnceAbout(nsIDocument::eMutationEvent);
if (aEventMessage == eLegacyAttrModified) {
doc->WarnOnceAbout(nsIDocument::eDOMAttrModifiedEvent);
}
}
// If aEventMessage is eLegacySubtreeModified, we need to listen all
// mutations. nsContentUtils::HasMutationListeners relies on this.

View File

@ -103,17 +103,17 @@ static NPNetscapeFuncs sBrowserFuncs = {
_geturl,
_posturl,
_requestread,
nullptr,
nullptr,
nullptr,
nullptr, // _newstream, unimplemented
nullptr, // _write, unimplemented
nullptr, // _destroystream, unimplemented
_status,
_useragent,
_memalloc,
_memfree,
_memflush,
_reloadplugins,
_getJavaEnv,
_getJavaPeer,
nullptr, // _getJavaEnv, unimplemented
nullptr, // _getJavaPeer, unimplemented
_geturlnotify,
_posturlnotify,
_getvalue,
@ -1702,14 +1702,6 @@ _requestread(NPStream *pstream, NPByteRange *rangeList)
return NPERR_STREAM_NOT_SEEKABLE;
}
// Deprecated, only stubbed out
void* /* OJI type: JRIEnv* */
_getJavaEnv()
{
NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_GetJavaEnv\n"));
return nullptr;
}
const char *
_useragent(NPP npp)
{
@ -1743,14 +1735,6 @@ _memalloc (uint32_t size)
return moz_xmalloc(size);
}
// Deprecated, only stubbed out
void* /* OJI type: jref */
_getJavaPeer(NPP npp)
{
NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_GetJavaPeer: npp=%p\n", (void*)npp));
return nullptr;
}
void
_pushpopupsenabledstate(NPP npp, NPBool enabled)
{

View File

@ -279,13 +279,6 @@ _useragent(NPP npp);
void*
_memalloc (uint32_t size);
// Deprecated entry points for the old Java plugin.
void* /* OJI type: JRIEnv* */
_getJavaEnv();
void* /* OJI type: jref */
_getJavaPeer(NPP npp);
void
_urlredirectresponse(NPP instance, void* notifyData, NPBool allow);

View File

@ -59,7 +59,6 @@ nsNPAPIPluginInstance::nsNPAPIPluginInstance()
#ifdef XP_MACOSX
, mCurrentPluginEvent(nullptr)
#endif
, mHaveJavaC2PJSObjectQuirk(false)
, mCachedParamLength(0)
, mCachedParamNames(nullptr)
, mCachedParamValues(nullptr)

View File

@ -298,9 +298,6 @@ private:
// This is only valid when the plugin is actually stopped!
mozilla::TimeStamp mStopTime;
// is this instance Java and affected by bug 750480?
bool mHaveJavaC2PJSObjectQuirk;
static uint32_t gInUnsafePluginCalls;
// The arrays can only be released when the plugin instance is destroyed,

View File

@ -875,14 +875,6 @@ _useragent(NPP aNPP);
static void*
_memalloc (uint32_t size);
// Deprecated entry points for the old Java plugin.
static void* /* OJI type: JRIEnv* */
_getjavaenv(void);
// Deprecated entry points for the old Java plugin.
static void* /* OJI type: jref */
_getjavapeer(NPP aNPP);
static bool
_invoke(NPP aNPP, NPObject* npobj, NPIdentifier method, const NPVariant *args,
uint32_t argCount, NPVariant *result);
@ -978,17 +970,17 @@ const NPNetscapeFuncs PluginModuleChild::sBrowserFuncs = {
mozilla::plugins::child::_geturl,
mozilla::plugins::child::_posturl,
mozilla::plugins::child::_requestread,
nullptr,
nullptr,
nullptr,
nullptr, // _newstream, unimplemented
nullptr, // _write, unimplemented
nullptr, // _destroystream, unimplemented
mozilla::plugins::child::_status,
mozilla::plugins::child::_useragent,
mozilla::plugins::child::_memalloc,
mozilla::plugins::child::_memfree,
mozilla::plugins::child::_memflush,
mozilla::plugins::child::_reloadplugins,
mozilla::plugins::child::_getjavaenv,
mozilla::plugins::child::_getjavapeer,
nullptr, // _getjavaenv, unimplemented
nullptr, // _getjavapeer, unimplemented
mozilla::plugins::child::_geturlnotify,
mozilla::plugins::child::_posturlnotify,
mozilla::plugins::child::_getvalue,
@ -1304,21 +1296,6 @@ _memalloc(uint32_t aSize)
return moz_xmalloc(aSize);
}
// Deprecated entry points for the old Java plugin.
void* /* OJI type: JRIEnv* */
_getjavaenv(void)
{
PLUGIN_LOG_DEBUG_FUNCTION;
return 0;
}
void* /* OJI type: jref */
_getjavapeer(NPP aNPP)
{
PLUGIN_LOG_DEBUG_FUNCTION;
return 0;
}
bool
_invoke(NPP aNPP,
NPObject* aNPObj,

View File

@ -135,7 +135,6 @@ static bool setPluginWantsAllStreams(NPObject* npobj, const NPVariant* args, uin
static bool crashPlugin(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
static bool crashOnDestroy(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
static bool getObjectValue(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
static bool getJavaCodebase(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
static bool checkObjectValue(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
static bool enableFPExceptions(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
static bool hangPlugin(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
@ -207,7 +206,6 @@ static const NPUTF8* sPluginMethodIdentifierNames[] = {
"crash",
"crashOnDestroy",
"getObjectValue",
"getJavaCodebase",
"checkObjectValue",
"enableFPExceptions",
"hang",
@ -280,7 +278,6 @@ static const ScriptableFunction sPluginMethodFunctions[] = {
crashPlugin,
crashOnDestroy,
getObjectValue,
getJavaCodebase,
checkObjectValue,
enableFPExceptions,
hangPlugin,
@ -882,11 +879,6 @@ NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char*
if (strcmp(argn[i], "bugmode") == 0) {
instanceData->bugMode = atoi(argv[i]);
}
// Try to emulate java's codebase handling: Use the last seen codebase
// value, regardless of whether it is in attributes or params.
if (strcasecmp(argn[i], "codebase") == 0) {
instanceData->javaCodebase = argv[i];
}
// Bug 1307694 - There are two flash parameters that are order dependent for
// scaling/sizing the plugin. If they ever change from what is expected, it
@ -2724,20 +2716,6 @@ static const NPClass kTestSharedNPClass = {
// Everything else is nullptr
};
static bool getJavaCodebase(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
{
if (argCount != 0) {
return false;
}
NPP npp = static_cast<TestNPObject*>(npobj)->npp;
InstanceData* id = static_cast<InstanceData*>(npp->pdata);
char *outval = NPN_StrDup(id->javaCodebase.c_str());
STRINGZ_TO_NPVARIANT(outval, *result);
return true;
}
static bool getObjectValue(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
{
NPP npp = static_cast<TestNPObject*>(npobj)->npp;

View File

@ -141,7 +141,6 @@ typedef struct InstanceData {
bool wantsAllStreams;
int32_t mouseUpEventCount;
int32_t bugMode;
std::string javaCodebase;
AsyncDrawing asyncDrawing;
NPAsyncSurface *frontBuffer;
NPAsyncSurface *backBuffer;

View File

@ -521,17 +521,17 @@ public:
};
class SendMessageEventRunnable final : public ExtendableEventWorkerRunnable
, public StructuredCloneHolder
{
StructuredCloneHolder mData;
const ClientInfoAndState mClientInfoAndState;
public:
SendMessageEventRunnable(WorkerPrivate* aWorkerPrivate,
KeepAliveToken* aKeepAliveToken,
StructuredCloneHolder&& aData,
const ClientInfoAndState& aClientInfoAndState)
: ExtendableEventWorkerRunnable(aWorkerPrivate, aKeepAliveToken)
, mData(Move(aData))
, StructuredCloneHolder(CloningSupported, TransferringSupported,
JS::StructuredCloneScope::SameProcessDifferentThread)
, mClientInfoAndState(aClientInfoAndState)
{
MOZ_ASSERT(NS_IsMainThread());
@ -543,13 +543,13 @@ public:
JS::Rooted<JS::Value> messageData(aCx);
nsCOMPtr<nsIGlobalObject> sgo = aWorkerPrivate->GlobalScope();
ErrorResult rv;
mData.Read(sgo, aCx, &messageData, rv);
Read(sgo, aCx, &messageData, rv);
if (NS_WARN_IF(rv.Failed())) {
return true;
}
Sequence<OwningNonNull<MessagePort>> ports;
if (!mData.TakeTransferredPortsAsSequence(ports)) {
if (!TakeTransferredPortsAsSequence(ports)) {
return true;
}
@ -640,17 +640,6 @@ ServiceWorkerPrivate::SendMessageEvent(ipc::StructuredCloneData&& aData,
JS::Rooted<JS::Value> transferable(cx);
transferable.setObject(*array);
StructuredCloneHolder holder(StructuredCloneHolder::CloningSupported,
StructuredCloneHolder::TransferringSupported,
JS::StructuredCloneScope::DifferentProcess);
holder.Write(cx, messageData, transferable, JS::CloneDataPolicy(), rv);
if (rv.Failed()) {
return rv.StealNSResult();
}
// Now that the re-packing is complete, send a runnable to the service worker
// thread.
rv = SpawnWorkerIfNeeded(MessageEvent);
if (NS_WARN_IF(rv.Failed())) {
return rv.StealNSResult();
@ -658,8 +647,13 @@ ServiceWorkerPrivate::SendMessageEvent(ipc::StructuredCloneData&& aData,
RefPtr<KeepAliveToken> token = CreateEventKeepAliveToken();
RefPtr<SendMessageEventRunnable> runnable =
new SendMessageEventRunnable(mWorkerPrivate, token, Move(holder),
aClientInfoAndState);
new SendMessageEventRunnable(mWorkerPrivate, token, aClientInfoAndState);
runnable->Write(cx, messageData, transferable, JS::CloneDataPolicy(), rv);
if (rv.Failed()) {
return rv.StealNSResult();
}
if (!runnable->Dispatch()) {
return NS_ERROR_FAILURE;
}

View File

@ -186,7 +186,7 @@ partial interface Navigator {
readonly attribute DOMString buildID;
// WebKit/Blink/Trident/Presto support this.
[Throws, NeedsCallerType]
[Affects=Nothing, DependsOn=Nothing]
boolean javaEnabled();
/**

View File

@ -119,6 +119,7 @@ public:
EndTransactionFlags aFlags = END_DEFAULT) = 0;
virtual void UpdateRenderBounds(const gfx::IntRect& aRect) {}
virtual void SetDiagnosticTypes(DiagnosticTypes aDiagnostics) {}
virtual void InvalidateAll() = 0;
virtual HostLayerManager* AsHostLayerManager() override {
return this;
@ -406,6 +407,10 @@ public:
mCompositor->SetDiagnosticTypes(aDiagnostics);
}
virtual void InvalidateAll() override {
AddInvalidRegion(nsIntRegion(mRenderBounds));
}
void ForcePresent() override { mCompositor->ForcePresent(); }
private:

View File

@ -642,9 +642,8 @@ CompositorBridgeParent::RecvNotifyRegionInvalidated(const nsIntRegion& aRegion)
void
CompositorBridgeParent::Invalidate()
{
if (mLayerManager && mLayerManager->GetRoot()) {
mLayerManager->AddInvalidRegion(
mLayerManager->GetRoot()->GetLocalVisibleRegion().ToUnknownRegion().GetBounds());
if (mLayerManager) {
mLayerManager->InvalidateAll();
}
}

View File

@ -69,6 +69,10 @@ public:
void NotifyShadowTreeTransaction() override;
void UpdateRenderBounds(const gfx::IntRect& aRect) override;
void InvalidateAll() override {
AddInvalidRegion(nsIntRegion(mRenderBounds));
}
LayerManagerMLGPU* AsLayerManagerMLGPU() override {
return this;
}

View File

@ -201,12 +201,6 @@ opt = args.jemalloc
if opt is not None:
CONFIGURE_ARGS += (" --enable-jemalloc" if opt else " --disable-jemalloc")
# Any jobs that wish to produce additional output can save them into the upload
# directory if there is such a thing, falling back to OBJDIR.
env.setdefault('MOZ_UPLOAD_DIR', OBJDIR)
ensure_dir_exists(env['MOZ_UPLOAD_DIR'], clobber=False, creation_marker_filename=None)
info("MOZ_UPLOAD_DIR = {}".format(env['MOZ_UPLOAD_DIR']))
# Some of the variants request a particular word size (eg ARM simulators).
word_bits = variant.get('bits')
@ -314,6 +308,12 @@ timer.start()
ensure_dir_exists(OBJDIR, clobber=not args.dep and not args.nobuild)
ensure_dir_exists(OUTDIR, clobber=not args.keep)
# Any jobs that wish to produce additional output can save them into the upload
# directory if there is such a thing, falling back to OBJDIR.
env.setdefault('MOZ_UPLOAD_DIR', OBJDIR)
ensure_dir_exists(env['MOZ_UPLOAD_DIR'], clobber=False, creation_marker_filename=None)
info("MOZ_UPLOAD_DIR = {}".format(env['MOZ_UPLOAD_DIR']))
def run_command(command, check=False, **kwargs):
kwargs.setdefault('cwd', OBJDIR)

View File

@ -0,0 +1,15 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/ */
var BUGNUMBER = '523401';
var summary = 'numeric literal followed by an identifier';
var array = new Array();
assertThrowsInstanceOf(() => eval("array[0for]"), SyntaxError);
assertThrowsInstanceOf(() => eval("array[1yield]"), SyntaxError);
assertThrowsInstanceOf(() => eval("array[2in []]"), SyntaxError); // "2 in []" is valid.
reportCompare(array[2 in []], undefined);
reportCompare(2 in [], false);
assertThrowsInstanceOf(() => eval("array[3in]"), SyntaxError);
if (typeof reportCompare === "function")
reportCompare(0, 0);

View File

View File

@ -557,8 +557,188 @@ var XPCOMUtils = {
writable: false
});
},
/**
* Defines a proxy which acts as a lazy object getter that can be passed
* around as a reference, and will only be evaluated when something in
* that object gets accessed.
*
* The evaluation can be triggered by a function call, by getting or
* setting a property, calling this as a constructor, or enumerating
* the properties of this object (e.g. during an iteration).
*
* Please note that, even after evaluated, the object given to you
* remains being the proxy object (which forwards everything to the
* real object). This is important to correctly use these objects
* in pairs of add+remove listeners, for example.
* If your use case requires access to the direct object, you can
* get it through the untrap callback.
*
* @param aObject
* The object to define the lazy getter on.
*
* You can pass null to aObject if you just want to get this
* proxy through the return value.
*
* @param aName
* The name of the getter to define on aObject.
*
* @param aInitFuncOrResource
* A function or a module that defines what this object actually
* should be when it gets evaluated. This will only ever be called once.
*
* Short-hand: If you pass a string to this parameter, it will be treated
* as the URI of a module to be imported, and aName will be used as
* the symbol to retrieve from the module.
*
* @param aStubProperties
* In this parameter, you can provide an object which contains
* properties from the original object that, when accessed, will still
* prevent the entire object from being evaluated.
*
* These can be copies or simplified versions of the original properties.
*
* One example is to provide an alternative QueryInterface implementation
* to avoid the entire object from being evaluated when it's added as an
* observer (as addObserver calls object.QueryInterface(Ci.nsIObserver)).
*
* Once the object has been evaluated, the properties from the real
* object will be used instead of the ones provided here.
*
* @param aUntrapCallback
* A function that gets called once when the object has just been evaluated.
* You can use this to do some work (e.g. setting properties) that you need
* to do on this object but that can wait until it gets evaluated.
*
* Another use case for this is to use during code development to log when
* this object gets evaluated, to make sure you're not accidentally triggering
* it earlier than expected.
*/
defineLazyProxy: function XPCOMUtils__defineLazyProxy(aObject, aName, aInitFuncOrResource,
aStubProperties, aUntrapCallback) {
let initFunc = aInitFuncOrResource;
if (typeof(aInitFuncOrResource) == "string") {
initFunc = function () {
let tmp = {};
ChromeUtils.import(aInitFuncOrResource, tmp);
return tmp[aName];
};
}
let handler = new LazyProxyHandler(aName, initFunc,
aStubProperties, aUntrapCallback);
/*
* We cannot simply create a lazy getter for the underlying
* object and pass it as the target of the proxy, because
* just passing it in `new Proxy` means it would get
* evaluated. Becase of this, a full handler needs to be
* implemented (the LazyProxyHandler).
*
* So, an empty object is used as the target, and the handler
* replaces it on every call with the real object.
*/
let proxy = new Proxy({}, handler);
if (aObject) {
Object.defineProperty(aObject, aName, {
value: proxy,
enumerable: true,
writable: true,
});
}
return proxy;
},
};
/**
* LazyProxyHandler
* This class implements the handler used
* in the proxy from defineLazyProxy.
*
* This handler forwards all calls to an underlying object,
* stored as `this.realObject`, which is obtained as the returned
* value from aInitFunc, which will be called on the first time
* time that it needs to be used (with an exception in the get() trap
* for the properties provided in the `aStubProperties` parameter).
*/
class LazyProxyHandler {
constructor(aName, aInitFunc, aStubProperties, aUntrapCallback) {
this.pending = true;
this.name = aName;
this.initFuncOrResource = aInitFunc;
this.stubProperties = aStubProperties;
this.untrapCallback = aUntrapCallback;
}
getObject() {
if (this.pending) {
this.realObject = this.initFuncOrResource.call(null);
if (this.untrapCallback) {
this.untrapCallback.call(null, this.realObject);
this.untrapCallback = null;
}
this.pending = false;
this.stubProperties = null;
}
return this.realObject;
}
getPrototypeOf(target) {
return Reflect.getPrototypeOf(this.getObject());
}
setPrototypeOf(target, prototype) {
return Reflect.setPrototypeOf(this.getObject(), prototype);
}
isExtensible(target) {
return Reflect.isExtensible(this.getObject());
}
preventExtensions(target) {
return Reflect.preventExtensions(this.getObject());
}
getOwnPropertyDescriptor(target, prop) {
return Reflect.getOwnPropertyDescriptor(this.getObject(), prop);
}
defineProperty(target, prop, descriptor) {
return Reflect.defineProperty(this.getObject(), prop, descriptor);
}
has(target, prop) {
return Reflect.has(this.getObject(), prop);
}
get(target, prop, receiver) {
if (this.pending &&
this.stubProperties &&
Object.prototype.hasOwnProperty.call(this.stubProperties, prop)) {
return this.stubProperties[prop];
}
return Reflect.get(this.getObject(), prop, receiver);
}
set(target, prop, value, receiver) {
return Reflect.set(this.getObject(), prop, value, receiver);
}
deleteProperty(target, prop) {
return Reflect.deleteProperty(this.getObject(), prop);
}
ownKeys(target) {
return Reflect.ownKeys(this.getObject());
}
}
var XPCU_lazyPreferenceObserverQI = ChromeUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]);
ChromeUtils.defineModuleGetter(this, "Services",

View File

@ -0,0 +1,113 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* This file tests the method defineLazyProxy from XPCOMUtils.jsm.
*/
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
add_task(function test_lazy_proxy() {
let tmp = {};
let realObject = {
"prop1": "value1",
"prop2": "value2",
};
let evaluated = false;
let untrapCalled = false;
let lazyProxy = XPCOMUtils.defineLazyProxy(
tmp,
"myLazyProxy",
// Initiliazer function
function init() {
evaluated = true;
return realObject;
},
// Stub properties
{
"prop1": "stub"
},
// Untrap callback
function untrapCallback(obj) {
Assert.equal(obj, realObject, "The underlying object can be obtained in the untrap callback");
untrapCalled = true;
}
);
// Check that the proxy returned and the one
// defined in tmp are the same.
//
// Note: Assert.strictEqual can't be used here
// because it wants to stringify the two objects
// compared, which defeats the lazy proxy.
Assert.ok(lazyProxy === tmp.myLazyProxy, "Return value and object defined are the same");
Assert.ok(Cu.isProxy(lazyProxy), "Returned value is in fact a proxy");
// Check that just using the proxy above didn't
// trigger the lazy getter evaluation.
Assert.ok(!evaluated, "The lazy proxy hasn't been evaluated yet");
Assert.ok(!untrapCalled, "The untrap callback hasn't been called yet");
// Accessing a stubbed property returns the stub
// value and doesn't trigger evaluation.
Assert.equal(lazyProxy.prop1, "stub", "Accessing a stubbed property returns the stubbed value");
Assert.ok(!evaluated, "The access to the stubbed property above didn't evaluate the lazy proxy");
Assert.ok(!untrapCalled, "The untrap callback hasn't been called yet");
// Now the access to another property will trigger
// the evaluation, as expected.
Assert.equal(lazyProxy.prop2, "value2", "Property access is correctly forwarded to the underlying object");
Assert.ok(evaluated, "Accessing a non-stubbed property triggered the proxy evaluation");
Assert.ok(untrapCalled, "The untrap callback was called");
// The value of prop1 is now the real value and not the stub value.
Assert.equal(lazyProxy.prop1, "value1", "The value of prop1 is now the real value and not the stub one");
});
add_task(function test_module_version() {
// Test that passing a string instead of an initialization function
// makes this behave like a lazy module getter.
const NET_UTIL_URI = "resource://gre/modules/NetUtil.jsm";
let underlyingObject;
Cu.unload(NET_UTIL_URI);
let lazyProxy = XPCOMUtils.defineLazyProxy(
null,
"NetUtil",
NET_UTIL_URI,
null, /* no stubs */
function untrapCallback(object) {
underlyingObject = object;
}
);
Assert.ok(!Cu.isModuleLoaded(NET_UTIL_URI), "The NetUtil module was not loaded by the lazy proxy definition");
// Access the object, which will evaluate the proxy.
lazyProxy.foo = "bar";
// Module was loaded.
Assert.ok(Cu.isModuleLoaded(NET_UTIL_URI), "The NetUtil module was loaded");
let { NetUtil } = ChromeUtils.import(NET_UTIL_URI, {});
// Avoids a gigantic stringification in the logs.
Assert.ok(NetUtil === underlyingObject, "The module loaded is the same as the one directly obtained by ChromeUtils.import");
// Proxy correctly passed the setter to the underlying object.
Assert.equal(NetUtil.foo, "bar", "Proxy correctly passed the setter to the underlying object");
delete lazyProxy.foo;
// Proxy correctly passed the delete operation to the underlying object.
Assert.ok(!NetUtil.hasOwnProperty("foo"), "Proxy correctly passed the delete operation to the underlying object");
});

View File

@ -93,6 +93,7 @@ head = head_ongc.js
[test_recursive_import.js]
[test_xpcomutils.js]
[test_unload.js]
[test_lazyproxy.js]
[test_attributes.js]
[test_params.js]
[test_tearoffs.js]

View File

@ -10197,10 +10197,10 @@ PaintTelemetry::AutoRecordPaint::~AutoRecordPaint()
uint32_t amount = static_cast<int32_t>((aDurationMs / totalMs) * 100.0);
Telemetry::Accumulate(Telemetry::CONTENT_LARGE_PAINT_PHASE_WEIGHT, aKey, amount);
};
auto recordSmall = [=](const nsString& aKey, double aDurationMs) -> void {
auto recordSmall = [=](const nsCString& aKey, double aDurationMs) -> void {
MOZ_ASSERT(aDurationMs <= totalMs);
uint32_t amount = static_cast<int32_t>((aDurationMs / totalMs) * 100.0);
Telemetry::ScalarAdd(Telemetry::ScalarID::GFX_SMALL_PAINT_PHASE_WEIGHT, aKey, amount);
Telemetry::Accumulate(Telemetry::CONTENT_SMALL_PAINT_PHASE_WEIGHT, aKey, amount);
};
double dlMs = sMetrics[Metric::DisplayList];
@ -10214,9 +10214,9 @@ PaintTelemetry::AutoRecordPaint::~AutoRecordPaint()
recordLarge(NS_LITERAL_CSTRING("flb"), flbMs);
recordLarge(NS_LITERAL_CSTRING("r"), rMs);
} else {
recordSmall(NS_LITERAL_STRING("dl"), dlMs);
recordSmall(NS_LITERAL_STRING("flb"), flbMs);
recordSmall(NS_LITERAL_STRING("r"), rMs);
recordSmall(NS_LITERAL_CSTRING("dl"), dlMs);
recordSmall(NS_LITERAL_CSTRING("flb"), flbMs);
recordSmall(NS_LITERAL_CSTRING("r"), rMs);
}
}

View File

@ -315,11 +315,7 @@ public:
bool isNothing() const { return !mIsSome; }
/* Returns the contents of this Maybe<T> by value. Unsafe unless |isSome()|. */
T value() const
{
MOZ_ASSERT(mIsSome);
return ref();
}
T value() const;
/*
* Returns the contents of this Maybe<T> by value. If |isNothing()|, returns
@ -348,17 +344,8 @@ public:
}
/* Returns the contents of this Maybe<T> by pointer. Unsafe unless |isSome()|. */
T* ptr()
{
MOZ_ASSERT(mIsSome);
return &ref();
}
const T* ptr() const
{
MOZ_ASSERT(mIsSome);
return &ref();
}
T* ptr();
const T* ptr() const;
/*
* Returns the contents of this Maybe<T> by pointer. If |isNothing()|,
@ -402,30 +389,12 @@ public:
return aFunc();
}
T* operator->()
{
MOZ_ASSERT(mIsSome);
return ptr();
}
const T* operator->() const
{
MOZ_ASSERT(mIsSome);
return ptr();
}
T* operator->();
const T* operator->() const;
/* Returns the contents of this Maybe<T> by ref. Unsafe unless |isSome()|. */
T& ref()
{
MOZ_ASSERT(mIsSome);
return *static_cast<T*>(data());
}
const T& ref() const
{
MOZ_ASSERT(mIsSome);
return *static_cast<const T*>(data());
}
T& ref();
const T& ref() const;
/*
* Returns the contents of this Maybe<T> by ref. If |isNothing()|, returns
@ -469,17 +438,8 @@ public:
return aFunc();
}
T& operator*()
{
MOZ_ASSERT(mIsSome);
return ref();
}
const T& operator*() const
{
MOZ_ASSERT(mIsSome);
return ref();
}
T& operator*();
const T& operator*() const;
/* If |isSome()|, runs the provided function or functor on the contents of
* this Maybe. */
@ -544,12 +504,7 @@ public:
* arguments to |emplace()| are the parameters to T's constructor.
*/
template<typename... Args>
void emplace(Args&&... aArgs)
{
MOZ_ASSERT(!mIsSome);
::new (KnownNotNull, data()) T(Forward<Args>(aArgs)...);
mIsSome = true;
}
void emplace(Args&&... aArgs);
friend std::ostream&
operator<<(std::ostream& aStream, const Maybe<T>& aMaybe)
@ -563,6 +518,88 @@ public:
}
};
template<typename T>
T
Maybe<T>::value() const
{
MOZ_DIAGNOSTIC_ASSERT(mIsSome);
return ref();
}
template<typename T>
T*
Maybe<T>::ptr()
{
MOZ_DIAGNOSTIC_ASSERT(mIsSome);
return &ref();
}
template<typename T>
const T*
Maybe<T>::ptr() const
{
MOZ_DIAGNOSTIC_ASSERT(mIsSome);
return &ref();
}
template<typename T>
T*
Maybe<T>::operator->()
{
MOZ_DIAGNOSTIC_ASSERT(mIsSome);
return ptr();
}
template<typename T>
const T*
Maybe<T>::operator->() const
{
MOZ_DIAGNOSTIC_ASSERT(mIsSome);
return ptr();
}
template<typename T>
T&
Maybe<T>::ref()
{
MOZ_DIAGNOSTIC_ASSERT(mIsSome);
return *static_cast<T*>(data());
}
template<typename T>
const T&
Maybe<T>::ref() const
{
MOZ_DIAGNOSTIC_ASSERT(mIsSome);
return *static_cast<const T*>(data());
}
template<typename T>
T&
Maybe<T>::operator*()
{
MOZ_DIAGNOSTIC_ASSERT(mIsSome);
return ref();
}
template<typename T>
const T&
Maybe<T>::operator*() const
{
MOZ_DIAGNOSTIC_ASSERT(mIsSome);
return ref();
}
template<typename T>
template<typename... Args>
void
Maybe<T>::emplace(Args&&... aArgs)
{
MOZ_DIAGNOSTIC_ASSERT(!mIsSome);
::new (KnownNotNull, data()) T(Forward<Args>(aArgs)...);
mIsSome = true;
}
/*
* Some() creates a Maybe<T> value containing the provided T value. If T has a
* move constructor, it's used to make this as efficient as possible.

View File

@ -396,6 +396,9 @@ class NavigationDelegateTest : BaseSessionTest() {
@WithDevToolsAPI
@Test fun onNewSession_calledForTargetBlankLink() {
// Disable popup blocker.
sessionRule.setPrefsUntilTestEnd(mapOf("dom.disable_open_during_load" to false))
sessionRule.session.loadTestPath(NEW_SESSION_HTML_PATH)
sessionRule.session.waitForPageStop()
@ -433,6 +436,9 @@ class NavigationDelegateTest : BaseSessionTest() {
@WithDevToolsAPI
@Test fun onNewSession_childShouldLoad() {
// Disable popup blocker.
sessionRule.setPrefsUntilTestEnd(mapOf("dom.disable_open_during_load" to false))
sessionRule.session.loadTestPath(NEW_SESSION_HTML_PATH)
sessionRule.session.waitForPageStop()
@ -455,6 +461,9 @@ class NavigationDelegateTest : BaseSessionTest() {
@WithDevToolsAPI
@Test fun onNewSession_setWindowOpener() {
// Disable popup blocker.
sessionRule.setPrefsUntilTestEnd(mapOf("dom.disable_open_during_load" to false))
sessionRule.session.loadTestPath(NEW_SESSION_HTML_PATH)
sessionRule.session.waitForPageStop()
@ -469,6 +478,9 @@ class NavigationDelegateTest : BaseSessionTest() {
@WithDevToolsAPI
@Test fun onNewSession_supportNoOpener() {
// Disable popup blocker.
sessionRule.setPrefsUntilTestEnd(mapOf("dom.disable_open_during_load" to false))
sessionRule.session.loadTestPath(NEW_SESSION_HTML_PATH)
sessionRule.session.waitForPageStop()
@ -482,6 +494,9 @@ class NavigationDelegateTest : BaseSessionTest() {
@WithDevToolsAPI
@Test fun onNewSession_notCalledForHandledLoads() {
// Disable popup blocker.
sessionRule.setPrefsUntilTestEnd(mapOf("dom.disable_open_during_load" to false))
sessionRule.session.loadTestPath(NEW_SESSION_HTML_PATH)
sessionRule.session.waitForPageStop()
@ -514,6 +529,9 @@ class NavigationDelegateTest : BaseSessionTest() {
@WithDevToolsAPI
@Test(expected = IllegalArgumentException::class)
fun onNewSession_doesNotAllowOpened() {
// Disable popup blocker.
sessionRule.setPrefsUntilTestEnd(mapOf("dom.disable_open_during_load" to false))
sessionRule.session.loadTestPath(NEW_SESSION_HTML_PATH)
sessionRule.session.waitForPageStop()

View File

@ -3103,11 +3103,6 @@ pref("plugins.navigator.hidden_ctp_plugin", "");
// The default value for nsIPluginTag.enabledState (STATE_ENABLED = 2)
pref("plugin.default.state", 2);
// The MIME type that should bind to legacy java-specific invocations like
// <applet> and <object data="java:foo">. Setting this to a non-java MIME type
// is undefined behavior.
pref("plugin.java.mime", "application/x-java-vm");
// How long in minutes we will allow a plugin to work after the user has chosen
// to allow it "now"
pref("plugin.sessionPermissionNow.intervalInMinutes", 60);

View File

@ -154,6 +154,11 @@ public:
return !!::FlushInstructionCache(::GetCurrentProcess(), nullptr, 0);
}
static DWORD GetTrampWriteProtFlags()
{
return PAGE_EXECUTE_READWRITE;
}
protected:
uint8_t* GetLocalView() const
{
@ -370,6 +375,11 @@ public:
return !!::FlushInstructionCache(mProcess, nullptr, 0);
}
static DWORD GetTrampWriteProtFlags()
{
return PAGE_READWRITE;
}
protected:
uint8_t* GetLocalView() const
{

View File

@ -30,7 +30,7 @@ public:
, mMaxOffset(aChunkSize)
, mAccumulatedStatus(true)
{
::VirtualProtect(aLocalBase, aChunkSize, PAGE_EXECUTE_READWRITE,
::VirtualProtect(aLocalBase, aChunkSize, MMPolicy::GetTrampWriteProtFlags(),
&mPrevLocalProt);
}

View File

@ -2706,32 +2706,6 @@ NS_LinkRedirectChannels(uint32_t channelId,
_result);
}
#define NS_FAKE_SCHEME "http://"
#define NS_FAKE_TLD ".invalid"
nsresult NS_MakeRandomInvalidURLString(nsCString &result)
{
nsresult rv;
nsCOMPtr<nsIUUIDGenerator> uuidgen =
do_GetService("@mozilla.org/uuid-generator;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsID idee;
rv = uuidgen->GenerateUUIDInPlace(&idee);
NS_ENSURE_SUCCESS(rv, rv);
char chars[NSID_LENGTH];
idee.ToProvidedString(chars);
result.AssignLiteral(NS_FAKE_SCHEME);
// Strip off the '{' and '}' at the beginning and end of the UUID
result.Append(chars + 1, NSID_LENGTH - 3);
result.AppendLiteral(NS_FAKE_TLD);
return NS_OK;
}
#undef NS_FAKE_SCHEME
#undef NS_FAKE_TLD
nsresult NS_MaybeOpenChannelUsingOpen2(nsIChannel* aChannel,
nsIInputStream **aStream)
{
@ -2752,64 +2726,6 @@ nsresult NS_MaybeOpenChannelUsingAsyncOpen2(nsIChannel* aChannel,
return aChannel->AsyncOpen(aListener, nullptr);
}
nsresult
NS_CheckIsJavaCompatibleURLString(nsCString &urlString, bool *result)
{
*result = false; // Default to "no"
nsresult rv = NS_OK;
nsCOMPtr<nsIURLParser> urlParser =
do_GetService(NS_STDURLPARSER_CONTRACTID, &rv);
if (NS_FAILED(rv) || !urlParser)
return NS_ERROR_FAILURE;
bool compatible = true;
uint32_t schemePos = 0;
int32_t schemeLen = 0;
urlParser->ParseURL(urlString.get(), -1, &schemePos, &schemeLen,
nullptr, nullptr, nullptr, nullptr);
if (schemeLen != -1) {
nsCString scheme;
scheme.Assign(urlString.get() + schemePos, schemeLen);
// By default Java only understands a small number of URL schemes, and of
// these only some can legitimately represent a browser page's "origin"
// (and be something we can legitimately expect Java to handle ... or not
// to mishandle).
//
// Besides those listed below, the OJI plugin understands the "jar",
// "mailto", "netdoc", "javascript" and "rmi" schemes, and Java Plugin2
// also understands the "about" scheme. We actually pass "about" URLs
// to Java ("about:blank" when processing a javascript: URL (one that
// calls Java) from the location bar of a blank page, and (in FF4 and up)
// "about:home" when processing a javascript: URL from the home page).
// And Java doesn't appear to mishandle them (for example it doesn't allow
// connections to "about" URLs). But it doesn't make any sense to do
// same-origin checks on "about" URLs, so we don't include them in our
// scheme whitelist.
//
// The OJI plugin doesn't understand "chrome" URLs (only Java Plugin2
// does) -- so we mustn't pass them to the OJI plugin. But we do need to
// pass "chrome" URLs to Java Plugin2: Java Plugin2 grants additional
// privileges to chrome "origins", and some extensions take advantage of
// this. For more information see bug 620773.
//
// As of FF4, we no longer support the OJI plugin.
if (PL_strcasecmp(scheme.get(), "http") &&
PL_strcasecmp(scheme.get(), "https") &&
PL_strcasecmp(scheme.get(), "file") &&
PL_strcasecmp(scheme.get(), "ftp") &&
PL_strcasecmp(scheme.get(), "gopher") &&
PL_strcasecmp(scheme.get(), "chrome"))
compatible = false;
} else {
compatible = false;
}
*result = compatible;
return NS_OK;
}
/** Given the first (disposition) token from a Content-Disposition header,
* tell whether it indicates the content is inline or attachment
* @param aDispToken the disposition token from the content-disposition header

View File

@ -849,12 +849,6 @@ nsresult NS_LinkRedirectChannels(uint32_t channelId,
nsIParentChannel *parentChannel,
nsIChannel **_result);
/**
* Helper function to create a random URL string that's properly formed
* but guaranteed to be invalid.
*/
nsresult NS_MakeRandomInvalidURLString(nsCString &result);
/**
* Helper function which checks whether the channel can be
* openend using Open2() or has to fall back to opening
@ -871,15 +865,6 @@ nsresult NS_MaybeOpenChannelUsingOpen2(nsIChannel* aChannel,
nsresult NS_MaybeOpenChannelUsingAsyncOpen2(nsIChannel* aChannel,
nsIStreamListener *aListener);
/**
* Helper function to determine whether urlString is Java-compatible --
* whether it can be passed to the Java URL(String) constructor without the
* latter throwing a MalformedURLException, or without Java otherwise
* mishandling it. This function (in effect) implements a scheme whitelist
* for Java.
*/
nsresult NS_CheckIsJavaCompatibleURLString(nsCString& urlString, bool *result);
/** Given the first (disposition) token from a Content-Disposition header,
* tell whether it indicates the content is inline or attachment
* @param aDispToken the disposition token from the content-disposition header

View File

@ -14,6 +14,7 @@
#include "nsIFile.h"
#include "nsNetCID.h"
#include "nsNetUtil.h"
#include "nsReadableUtils.h"
#include "nsURLHelper.h"
#include "nsEscape.h"
@ -306,8 +307,11 @@ SubstitutingProtocolHandler::SetSubstitution(const nsACString& root, nsIURI *bas
}
nsresult
SubstitutingProtocolHandler::SetSubstitutionWithFlags(const nsACString& root, nsIURI *baseURI, uint32_t flags)
SubstitutingProtocolHandler::SetSubstitutionWithFlags(const nsACString& origRoot, nsIURI *baseURI, uint32_t flags)
{
nsAutoCString root;
ToLowerCase(origRoot, root);
if (!baseURI) {
mSubstitutions.Remove(root);
NotifyObservers(root, baseURI);
@ -349,10 +353,13 @@ SubstitutingProtocolHandler::SetSubstitutionWithFlags(const nsACString& root, ns
}
nsresult
SubstitutingProtocolHandler::GetSubstitution(const nsACString& root, nsIURI **result)
SubstitutingProtocolHandler::GetSubstitution(const nsACString& origRoot, nsIURI **result)
{
NS_ENSURE_ARG_POINTER(result);
nsAutoCString root;
ToLowerCase(origRoot, root);
SubstitutionEntry entry;
if (mSubstitutions.Get(root, &entry)) {
nsCOMPtr<nsIURI> baseURI = entry.baseURI;
@ -367,6 +374,12 @@ SubstitutingProtocolHandler::GetSubstitution(const nsACString& root, nsIURI **re
nsresult
SubstitutingProtocolHandler::GetSubstitutionFlags(const nsACString& root, uint32_t* flags)
{
#ifdef DEBUG
nsAutoCString lcRoot;
ToLowerCase(root, lcRoot);
MOZ_ASSERT(root.Equals(lcRoot), "GetSubstitutionFlags should never receive mixed-case root name");
#endif
*flags = 0;
SubstitutionEntry entry;
if (mSubstitutions.Get(root, &entry)) {
@ -379,9 +392,13 @@ SubstitutingProtocolHandler::GetSubstitutionFlags(const nsACString& root, uint32
}
nsresult
SubstitutingProtocolHandler::HasSubstitution(const nsACString& root, bool *result)
SubstitutingProtocolHandler::HasSubstitution(const nsACString& origRoot, bool *result)
{
NS_ENSURE_ARG_POINTER(result);
nsAutoCString root;
ToLowerCase(origRoot, root);
*result = HasSubstitution(root);
return NS_OK;
}

View File

@ -25,8 +25,8 @@ interface nsISubstitutingProtocolHandler : nsIProtocolHandler
*
* A null baseURI removes the specified substitution.
*
* A root key should always be lowercase; however, this may not be
* enforced.
* The root key will be converted to lower-case to conform to
* case-insensitive URI hostname matching behavior.
*/
[must_use] void setSubstitution(in ACString root, in nsIURI baseURI);

View File

@ -0,0 +1,41 @@
"use strict";
ChromeUtils.import("resource://gre/modules/Services.jsm");
add_task(async function test_case_insensitive_substitutions() {
let resProto = Services.io.getProtocolHandler("resource")
.QueryInterface(Ci.nsISubstitutingProtocolHandler);
let uri = Services.io.newFileURI(do_get_file("data"));
resProto.setSubstitution("FooBar", uri);
resProto.setSubstitutionWithFlags("BarBaz", uri, 0);
equal(resProto.resolveURI(Services.io.newURI("resource://foobar/")),
uri.spec, "Got correct resolved URI for setSubstitution");
equal(resProto.resolveURI(Services.io.newURI("resource://foobar/")),
uri.spec, "Got correct resolved URI for setSubstitutionWithFlags");
ok(resProto.hasSubstitution("foobar"), "hasSubstitution works with all-lower-case root");
ok(resProto.hasSubstitution("FooBar"), "hasSubstitution works with mixed-case root");
equal(resProto.getSubstitution("foobar").spec, uri.spec,
"getSubstitution works with all-lower-case root");
equal(resProto.getSubstitution("FooBar").spec, uri.spec,
"getSubstitution works with mixed-case root");
resProto.setSubstitution("foobar", null);
resProto.setSubstitution("barbaz", null);
Assert.throws(() => resProto.resolveURI(Services.io.newURI("resource://foobar/")),
e => e.result == Cr.NS_ERROR_NOT_AVAILABLE,
"Correctly unregistered case-insensitive substitution in setSubstitution");
Assert.throws(() => resProto.resolveURI(Services.io.newURI("resource://barbaz/")),
e => e.result == Cr.NS_ERROR_NOT_AVAILABLE,
"Correctly unregistered case-insensitive substitution in setSubstitutionWithFlags");
Assert.throws(() => resProto.getSubstitution("foobar"),
e => e.result == Cr.NS_ERROR_NOT_AVAILABLE,
"foobar substitution has been removed");
});

View File

@ -421,3 +421,4 @@ run-sequentially = node server exceptions dont replay well
# http2-using tests require node available
skip-if = os == "android"
[test_ioservice.js]
[test_substituting_protocol_handler.js]

View File

@ -6,7 +6,7 @@ loader: taskgraph.loader.transform:loader
transforms:
- taskgraph.transforms.release_deps:transforms
- taskgraph.transforms.beetmover_cdns:transforms
- taskgraph.transforms.beetmover_push_to_release:transforms
- taskgraph.transforms.task:transforms
kind-dependencies:
@ -17,20 +17,20 @@ job-defaults:
shipping-phase: push
jobs:
fennec-push-to-cdns:
name: fennec_push_to_cdns
fennec-push-to-release:
name: fennec_push_to_release
product: fennec
shipping-product: fennec
treeherder-platform: Android/opt
treeherder-platform: fennec-release/opt
devedition-push-to-cdns:
name: devedition_push_to_cdns
devedition-push-to-release:
name: devedition_push_to_release
product: devedition
shipping-product: devedition
treeherder-platform: Linux64-devedition/opt
treeherder-platform: devedition-release/opt
firefox-push-to-cdns:
name: firefox_push_to_cdns
firefox-push-to-release:
name: firefox_push_to_release
product: firefox
shipping-product: firefox
treeherder-platform: Linux64/opt
treeherder-platform: firefox-release/opt

View File

@ -5,7 +5,7 @@
loader: taskgraph.loader.transform:loader
kind-dependencies:
- beetmover-cdns
- release-beetmover-push-to-release
transforms:
- taskgraph.transforms.release_deps:transforms

View File

@ -10,7 +10,7 @@ transforms:
- taskgraph.transforms.task:transforms
kind-dependencies:
- beetmover-cdns
- release-beetmover-push-to-release
job-defaults:
name: notify-release-drivers-push

View File

@ -10,7 +10,7 @@ transforms:
- taskgraph.transforms.task:transforms
kind-dependencies:
- beetmover-cdns
- release-beetmover-push-to-release
job-defaults:
description: Release Promotion version bump/tag

View File

@ -195,10 +195,11 @@ Beetmover-repackage is beetmover but for tasks that need an intermediate step
between signing and packaging, such as OSX. For more details see the definitions
of the Beetmover kind above and the repackage kind below.
beetmover-cdns
-------------------
release-beetmover-push-to-release
---------------------------------
Beetmover-cdns publishes promoted releases to CDNs. This is part of release promotion.
Beetmover-cdns publishes promoted releases from the candidates directory to the
release directory. This is part of release promotion.
beetmover-source
-------------------

View File

@ -356,6 +356,9 @@ def release_promotion_action(parameters, graph_config, input, task_group_id, tas
parameters['release_enable_partners'] = release_enable_partners
parameters['release_partners'] = input.get('release_partners')
parameters['release_enable_emefree'] = release_enable_emefree
# When doing staging releases on try, we still want to re-use tasks from
# previous graphs.
parameters['optimize_target_tasks'] = True
partner_config = input.get('release_partner_config')
if not partner_config and (release_enable_emefree or release_enable_partners):

View File

@ -2,7 +2,7 @@
# 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/.
"""
Transform the beetmover-cdns task into a task description.
Transform the beetmover-push-to-release task into a task description.
"""
from __future__ import absolute_import, print_function, unicode_literals
@ -30,7 +30,7 @@ taskref_or_string = Any(
basestring,
{Required('task-reference'): basestring})
beetmover_cdns_description_schema = Schema({
beetmover_push_to_release_description_schema = Schema({
Required('name'): basestring,
Required('product'): basestring,
Required('treeherder-platform'): basestring,
@ -52,13 +52,13 @@ def validate(config, jobs):
for job in jobs:
label = job['name']
validate_schema(
beetmover_cdns_description_schema, job,
"In cdns-signing ({!r} kind) task for {!r}:".format(config.kind, label))
beetmover_push_to_release_description_schema, job,
"In beetmover-push-to-release ({!r} kind) task for {!r}:".format(config.kind, label))
yield job
@transforms.add
def make_beetmover_cdns_description(config, jobs):
def make_beetmover_push_to_release_description(config, jobs):
for job in jobs:
treeherder = job.get('treeherder', {})
treeherder.setdefault('symbol', 'Rel(BM-C)')
@ -68,7 +68,7 @@ def make_beetmover_cdns_description(config, jobs):
label = job['name']
description = (
"Beetmover push to cdns for '{product}'".format(
"Beetmover push to release for '{product}'".format(
product=job['product']
)
)
@ -96,10 +96,10 @@ def make_beetmover_cdns_description(config, jobs):
@transforms.add
def make_beetmover_cdns_worker(config, jobs):
def make_beetmover_push_to_release_worker(config, jobs):
for job in jobs:
worker = {
'implementation': 'beetmover-cdns',
'implementation': 'beetmover-push-to-release',
'product': job['product'],
}
job["worker"] = worker

View File

@ -13,6 +13,7 @@ from taskgraph.util.schema import validate_schema, Schema
from taskgraph.util.scriptworker import (
get_signing_cert_scope,
get_worker_type_for_scope,
add_scope_prefix,
)
from taskgraph.transforms.task import task_description_schema
from voluptuous import Any, Required, Optional
@ -98,7 +99,7 @@ def make_checksums_signing_description(config, jobs):
'max-run-time': 3600},
'scopes': [
signing_cert_scope,
"project:releng:signing:format:gpg"
add_scope_prefix(config, 'signing:format:gpg'),
],
'dependencies': dependencies,
'attributes': attributes,

View File

@ -13,6 +13,7 @@ from taskgraph.util.schema import validate_schema, Schema
from taskgraph.util.scriptworker import (
get_signing_cert_scope,
get_worker_type_for_scope,
add_scope_prefix,
)
from taskgraph.util.taskcluster import get_artifact_path
from taskgraph.transforms.task import task_description_schema
@ -88,7 +89,7 @@ def make_release_generate_checksums_signing_description(config, jobs):
'max-run-time': 3600},
'scopes': [
signing_cert_scope,
"project:releng:signing:format:gpg"
add_scope_prefix(config, 'signing:format:gpg'),
],
'dependencies': dependencies,
'attributes': attributes,

View File

@ -13,6 +13,7 @@ from taskgraph.util.schema import validate_schema, Schema
from taskgraph.util.scriptworker import (
get_signing_cert_scope,
get_worker_type_for_scope,
add_scope_prefix,
)
from taskgraph.transforms.task import task_description_schema
from voluptuous import Any, Required, Optional
@ -88,7 +89,7 @@ def make_checksums_signing_description(config, jobs):
'max-run-time': 3600},
'scopes': [
signing_cert_scope,
"project:releng:signing:format:gpg"
add_scope_prefix(config, 'signing:format:gpg'),
],
'dependencies': dependencies,
'attributes': attributes,

View File

@ -465,7 +465,7 @@ task_description_schema = Schema({
Required('locale'): basestring,
}],
}, {
Required('implementation'): 'beetmover-cdns',
Required('implementation'): 'beetmover-push-to-release',
# the maximum time to run, in seconds
Required('max-run-time'): int,
@ -998,8 +998,8 @@ def build_beetmover_payload(config, task, task_def):
task_def['payload'].update(release_config)
@payload_builder('beetmover-cdns')
def build_beetmover_cdns_payload(config, task, task_def):
@payload_builder('beetmover-push-to-release')
def build_beetmover_push_to_release_payload(config, task, task_def):
worker = task['worker']
release_config = get_release_config(config)
@ -1219,7 +1219,7 @@ def set_defaults(config, tasks):
worker.setdefault('max-run-time', 600)
elif worker['implementation'] == 'beetmover':
worker.setdefault('max-run-time', 600)
elif worker['implementation'] == 'beetmover-cdns':
elif worker['implementation'] == 'beetmover-push-to-release':
worker.setdefault('max-run-time', 600)
elif worker['implementation'] == 'push-apk':
worker.setdefault('commit', False)

View File

@ -3988,14 +3988,6 @@
"n_buckets": 10,
"description": "Time spent scanning filesystem for plugins (ms)"
},
"CHECK_JAVA_ENABLED": {
"record_in_processes": ["main", "content"],
"expires_in_version": "default",
"kind": "exponential",
"high": 3000,
"n_buckets": 10,
"description": "Time spent checking if Java is enabled (ms)"
},
"PLUGIN_HANG_UI_USER_RESPONSE": {
"record_in_processes": ["main", "content"],
"expires_in_version": "never",
@ -12987,6 +12979,17 @@
"n_buckets": 10,
"description": "Percentage of time taken by phases in expensive content paints."
},
"CONTENT_SMALL_PAINT_PHASE_WEIGHT": {
"record_in_processes": ["main", "content"],
"alert_emails": ["mwoodrow@mozilla.com","gfx-telemetry-alerts@mozilla.com"],
"bug_numbers": [1430897],
"expires_in_version": "66",
"keyed": true,
"kind": "linear",
"high": 100,
"n_buckets": 10,
"description": "Percentage of time taken by phases in normal content paints."
},
"NARRATE_CONTENT_BY_LANGUAGE_2": {
"record_in_processes": ["main", "content"],
"alert_emails": ["eisaacson@mozilla.com"],

View File

@ -1318,24 +1318,6 @@ gfx.omtp:
record_in_processes:
- 'content'
gfx:
small_paint_phase_weight:
bug_numbers:
- 1430897
description: >
Time that is spent in each phase of painting, as a percentage of
paint time. See also CONTENT_LARGE_PAINT_PHASE_WEIGHT in Histograms.json.
Keys are r (rasterization), dl (display list construction), and flb
(FrameLayerBuilder).
keyed: true
kind: uint
expires: "66"
notification_emails:
- gfx-telemetry-alerts@mozilla.com
- mwoodrow@mozilla.com
record_in_processes:
- 'content'
# The following section contains the form autofill related scalars.
formautofill:
availability:

View File

@ -94,7 +94,6 @@
"CHARSET_OVERRIDE_SITUATION",
"CHARSET_OVERRIDE_USED",
"CHECK_ADDONS_MODIFIED_MS",
"CHECK_JAVA_ENABLED",
"COMPONENTS_SHIM_ACCESSED_BY_CONTENT",
"COMPOSITE_FRAME_ROUNDTRIP_TIME",
"COMPOSITE_TIME",
@ -601,7 +600,6 @@
"CHARSET_OVERRIDE_SITUATION",
"CHARSET_OVERRIDE_USED",
"CHECK_ADDONS_MODIFIED_MS",
"CHECK_JAVA_ENABLED",
"COMPONENTS_SHIM_ACCESSED_BY_CONTENT",
"COMPOSITE_FRAME_ROUNDTRIP_TIME",
"COMPOSITE_TIME",
@ -1435,7 +1433,6 @@
"PDF_VIEWER_TIME_TO_VIEW_MS",
"SSL_OCSP_MAY_FETCH",
"MOZ_SQLITE_OTHER_READ_B",
"CHECK_JAVA_ENABLED",
"TRANSLATION_OPPORTUNITIES",
"NEWTAB_PAGE_BLOCKED_SITES_COUNT",
"FX_SESSION_RESTORE_NUMBER_OF_TABS_RESTORED",

View File

@ -2471,6 +2471,7 @@ this.XPIDatabaseReconcile = {
let isDetectedInstall = isNewInstall && !aNewAddon;
// Load the manifest if necessary and sanity check the add-on ID
let unsigned;
try {
if (!aNewAddon) {
// Load the manifest from the add-on.
@ -2482,6 +2483,11 @@ this.XPIDatabaseReconcile = {
throw new Error("Invalid addon ID: expected addon ID " + aId +
", found " + aNewAddon.id + " in manifest");
}
unsigned = XPIDatabase.mustSign(aNewAddon.type) && !aNewAddon.isCorrectlySigned;
if (unsigned) {
throw Error(`Extension ${aNewAddon.id} is not correctly signed`);
}
} catch (e) {
logger.warn("addMetadata: Add-on " + aId + " is invalid", e);
@ -2491,6 +2497,8 @@ this.XPIDatabaseReconcile = {
logger.warn("Not uninstalling invalid item because it is a proxy file");
else if (aInstallLocation.locked)
logger.warn("Could not uninstall invalid item from locked install location");
else if (unsigned && !isNewInstall)
logger.warn("Not uninstalling existing unsigned add-on");
else
aInstallLocation.uninstallAddon(aId);
return null;

View File

@ -1 +0,0 @@
ChromeUtils.import("resource://xpcshell-data/BootstrapMonitor.jsm").monitor(this);

View File

@ -23,7 +23,5 @@ add_task(async function() {
await XPIProvider.verifySignatures();
let addon = await AddonManager.getAddonByID(ID);
Assert.equal(addon.signedState, AddonManager.SIGNEDSTATE_MISSING);
Assert.ok(!addon.isActive);
Assert.ok(addon.appDisabled);
Assert.equal(addon, null, "Unsigned extensions should not be installed at startup");
});

View File

@ -76,6 +76,10 @@ function promiseWriteRelativePointer(aId, aName) {
add_task(async function setup() {
ok(TEST_UNPACKED, "Pointer files only work with unpacked directories");
// Unpacked extensions are never signed, so this can only run with
// signature checks disabled.
Services.prefs.setBoolPref(PREF_XPI_SIGNATURES_REQUIRED, false);
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");
});

View File

@ -73,6 +73,10 @@ profileDir.append("extensions");
function run_test() {
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "2", "2");
// Unpacked extensions are never signed, so this can only run with
// signature checks disabled.
Services.prefs.setBoolPref(PREF_XPI_SIGNATURES_REQUIRED, false);
add_task(run_proxy_tests);
if (gHaveSymlinks)

View File

@ -8,6 +8,8 @@ createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "42");
BootstrapMonitor.init();
const BOOTSTRAP_JS = `ChromeUtils.import("resource://xpcshell-data/BootstrapMonitor.jsm").monitor(this);`;
// Ensure that a proxy file to an add-on with a valid manifest works.
add_task(async function() {
Services.prefs.setBoolPref(PREF_XPI_SIGNATURES_REQUIRED, false);
@ -15,23 +17,20 @@ add_task(async function() {
await promiseStartupManager();
let tempdir = gTmpD.clone();
await promiseWriteInstallRDFToDir({
let unpackedAddon = await promiseWriteInstallRDFToDir({
id: ID,
version: "1.0",
bootstrap: true,
unpack: true,
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}],
}],
name: "Test Bootstrap 1 (proxy)",
}, tempdir, ID, "bootstrap.js");
let unpackedAddon = tempdir.clone();
unpackedAddon.append(ID);
do_get_file("data/test_proxy/bootstrap.js")
.copyTo(unpackedAddon, "bootstrap.js");
}, tempdir, ID, {
"bootstrap.js": BOOTSTRAP_JS,
});
// create proxy file in profile/extensions dir
let extensionsDir = gProfD.clone();
@ -40,23 +39,30 @@ add_task(async function() {
await promiseRestartManager();
BootstrapMonitor.checkAddonInstalled(ID, "1.0");
BootstrapMonitor.checkAddonStarted(ID, "1.0");
let addon = await promiseAddonByID(ID);
Assert.notEqual(addon, null);
Assert.equal(addon.version, "1.0");
Assert.equal(addon.name, "Test Bootstrap 1 (proxy)");
Assert.ok(addon.isCompatible);
Assert.ok(!addon.appDisabled);
Assert.ok(addon.isActive);
Assert.equal(addon.type, "extension");
Assert.equal(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_UNKNOWN : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
if (AppConstants.MOZ_REQUIRE_SIGNING) {
BootstrapMonitor.checkAddonNotInstalled(ID, "1.0");
BootstrapMonitor.checkAddonNotStarted(ID, "1.0");
Assert.ok(proxyFile.exists());
Assert.equal(addon, null);
} else {
BootstrapMonitor.checkAddonInstalled(ID, "1.0");
BootstrapMonitor.checkAddonStarted(ID, "1.0");
addon.uninstall();
Assert.notEqual(addon, null);
Assert.equal(addon.version, "1.0");
Assert.equal(addon.name, "Test Bootstrap 1 (proxy)");
Assert.ok(addon.isCompatible);
Assert.ok(!addon.appDisabled);
Assert.ok(addon.isActive);
Assert.equal(addon.type, "extension");
Assert.equal(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_UNKNOWN : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
Assert.ok(proxyFile.exists());
addon.uninstall();
}
unpackedAddon.remove(true);
await promiseRestartManager();
@ -69,23 +75,20 @@ add_task(async function() {
let tempdir = gTmpD.clone();
// use a mismatched ID to make this install.rdf invalid
await promiseWriteInstallRDFToDir({
let unpackedAddon = await promiseWriteInstallRDFToDir({
id: "bad-proxy1@tests.mozilla.org",
version: "1.0",
bootstrap: true,
unpack: true,
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}],
}],
name: "Test Bootstrap 1 (proxy)",
}, tempdir, ID, "bootstrap.js");
let unpackedAddon = tempdir.clone();
unpackedAddon.append(ID);
do_get_file("data/test_proxy/bootstrap.js")
.copyTo(unpackedAddon, "bootstrap.js");
}, tempdir, ID, {
"bootstrap.js": BOOTSTRAP_JS,
});
// create proxy file in profile/extensions dir
let extensionsDir = gProfD.clone();

View File

@ -90,68 +90,6 @@ function verify_no_change([startFile, startState], [endFile, endState]) {
});
}
function verify_enables([startFile, startState], [endFile, endState]) {
add_task(async function() {
info("A switch from " + startFile + " to " + endFile + " should enable the add-on.");
// Install the first add-on
await manuallyInstall(do_get_file(DATA + startFile), profileDir, ID);
await promiseStartupManager();
let addon = await promiseAddonByID(ID);
Assert.notEqual(addon, null);
Assert.ok(!addon.isActive);
Assert.equal(addon.pendingOperations, AddonManager.PENDING_NONE);
Assert.equal(addon.signedState, startState);
// Swap in the files from the next add-on
manuallyUninstall(profileDir, ID);
await manuallyInstall(do_get_file(DATA + endFile), profileDir, ID);
let needsRestart = hasFlag(addon.operationsRequiringRestart, AddonManager.OP_NEEDS_RESTART_ENABLE);
info(needsRestart);
let events = {};
if (!needsRestart) {
events[ID] = [
["onPropertyChanged", ["appDisabled"]],
["onEnabling", false],
"onEnabled"
];
} else {
events[ID] = [
["onPropertyChanged", ["appDisabled"]],
"onEnabling"
];
}
if (startState != endState)
events[ID].unshift(["onPropertyChanged", ["signedState"]]);
prepare_test(events);
// Trigger the check
let changes = await verifySignatures();
Assert.equal(changes.enabled.length, 1);
Assert.equal(changes.enabled[0], ID);
Assert.equal(changes.disabled.length, 0);
Assert.ok(!addon.appDisabled);
if (needsRestart)
Assert.notEqual(addon.pendingOperations, AddonManager.PENDING_NONE);
else
Assert.ok(addon.isActive);
Assert.equal(addon.signedState, endState);
ensure_test_completed();
// Remove the add-on and restart to let it go away
manuallyUninstall(profileDir, ID);
await promiseRestartManager();
await promiseShutdownManager();
});
}
function verify_disables([startFile, startState], [endFile, endState]) {
add_task(async function() {
info("A switch from " + startFile + " to " + endFile + " should disable the add-on.");
@ -219,20 +157,8 @@ for (let start of GOOD) {
}
}
for (let start of BAD) {
for (let end of GOOD) {
verify_enables(start, end);
}
}
for (let start of GOOD) {
for (let end of GOOD.filter(f => f != start)) {
verify_no_change(start, end);
}
}
for (let start of BAD) {
for (let end of BAD.filter(f => f != start)) {
verify_no_change(start, end);
}
}

View File

@ -172,6 +172,14 @@ add_task(async function() {
let target;
if (!packed) {
// Unpacked extensions don't support signing, which means that
// our mock signing service is not able to give them a
// privileged signed state, and we can't install them on release
// builds.
if (!AppConstants.MOZ_ALLOW_LEGACY_EXTENSIONS) {
continue;
}
target = tempdir.clone();
target.append(ID);
@ -362,6 +370,11 @@ add_task(async function test_samefile() {
// Install a temporary add-on over the top of an existing add-on.
// Uninstall it and make sure the existing add-on comes back.
add_task(async function() {
// We can't install unpacked add-ons on release builds. See above.
if (!AppConstants.MOZ_ALLOW_LEGACY_EXTENSIONS) {
return;
}
await promiseInstallAllFiles([do_get_addon("test_bootstrap1_1")], true);
BootstrapMonitor.checkAddonInstalled(ID, "1.0");
@ -464,6 +477,11 @@ add_task(async function() {
// Install a temporary add-on as a version upgrade over the top of an
// existing temporary add-on.
add_task(async function() {
// We can't install unpacked add-ons on release builds. See above.
if (!AppConstants.MOZ_ALLOW_LEGACY_EXTENSIONS) {
return;
}
const tempdir = gTmpD.clone();
await promiseWriteInstallRDFToDir(sampleRDFManifest, tempdir, "bootstrap1@tests.mozilla.org", "bootstrap.js");
@ -515,6 +533,11 @@ add_task(async function() {
// Install a temporary add-on as a version downgrade over the top of an
// existing temporary add-on.
add_task(async function() {
// We can't install unpacked add-ons on release builds. See above.
if (!AppConstants.MOZ_ALLOW_LEGACY_EXTENSIONS) {
return;
}
const tempdir = gTmpD.clone();
await promiseWriteInstallRDFToDir(sampleRDFManifest, tempdir, "bootstrap1@tests.mozilla.org", "bootstrap.js");
@ -564,6 +587,11 @@ add_task(async function() {
// Installing a temporary add-on over an existing add-on with the same
// version number should be installed as an upgrade.
add_task(async function() {
// We can't install unpacked add-ons on release builds. See above.
if (!AppConstants.MOZ_ALLOW_LEGACY_EXTENSIONS) {
return;
}
const tempdir = gTmpD.clone();
await promiseWriteInstallRDFToDir(sampleRDFManifest, tempdir, "bootstrap1@tests.mozilla.org", "bootstrap.js");
@ -621,6 +649,11 @@ add_task(async function() {
// Install a temporary add-on over the top of an existing disabled add-on.
// After restart, the existing add-on should continue to be installed and disabled.
add_task(async function() {
// We can't install unpacked add-ons on release builds. See above.
if (!AppConstants.MOZ_ALLOW_LEGACY_EXTENSIONS) {
return;
}
await promiseInstallAllFiles([do_get_addon("test_bootstrap1_1")], true);
BootstrapMonitor.checkAddonInstalled(ID, "1.0");

View File

@ -10,3 +10,4 @@ tags = addons
tags = webextensions
[test_filepointer.js]
skip-if = !allow_legacy_extensions || require_signing