mirror of
https://github.com/Feodor2/Mypal68.git
synced 2025-06-18 14:55:44 -04:00
68.14.2 - everything else
This commit is contained in:
parent
40ed9513e6
commit
0ed4d27300
@ -655,9 +655,13 @@ class ContextMenuChild extends ActorChild {
|
||||
};
|
||||
|
||||
if (context.inFrame && !context.inSrcdocFrame) {
|
||||
data.frameReferrerInfo = E10SUtils.serializeReferrerInfo(
|
||||
doc.referrerInfo
|
||||
);
|
||||
if (isRemote) {
|
||||
data.frameReferrerInfo = E10SUtils.serializeReferrerInfo(
|
||||
doc.referrerInfo
|
||||
);
|
||||
} else {
|
||||
data.frameReferrerInfo = doc.referrerInfo;
|
||||
}
|
||||
}
|
||||
|
||||
if (linkReferrerInfo) {
|
||||
@ -962,9 +966,20 @@ class ContextMenuChild extends ActorChild {
|
||||
// currentRequestFinalURI. We should use that as the URL for purposes of
|
||||
// deciding on the filename, if it is present. It might not be present
|
||||
// if images are blocked.
|
||||
context.mediaURL = (
|
||||
context.target.currentRequestFinalURI || context.target.currentURI
|
||||
).spec;
|
||||
//
|
||||
// It is important to check both the final and the current URI, as they
|
||||
// could be different blob URIs, see bug 1625786.
|
||||
context.mediaURL = (() => {
|
||||
let finalURI = context.target.currentRequestFinalURI?.spec;
|
||||
if (finalURI && this._isMediaURLReusable(finalURI)) {
|
||||
return finalURI;
|
||||
}
|
||||
let currentURI = context.target.currentURI?.spec;
|
||||
if (currentURI && this._isMediaURLReusable(currentURI)) {
|
||||
return currentURI;
|
||||
}
|
||||
return "";
|
||||
})();
|
||||
|
||||
const descURL = context.target.getAttribute("longdesc");
|
||||
|
||||
|
@ -5,17 +5,10 @@
|
||||
var EXPORTED_SYMBOLS = ["OfflineAppsChild"];
|
||||
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
const { ActorChild } = ChromeUtils.import(
|
||||
"resource://gre/modules/ActorChild.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
E10SUtils: "resource://gre/modules/E10SUtils.jsm",
|
||||
});
|
||||
|
||||
class OfflineAppsChild extends ActorChild {
|
||||
constructor(dispatcher) {
|
||||
super(dispatcher);
|
||||
@ -24,15 +17,9 @@ class OfflineAppsChild extends ActorChild {
|
||||
this._docIdMap = new Map();
|
||||
|
||||
this._docManifestSet = new Set();
|
||||
|
||||
this._observerAdded = false;
|
||||
}
|
||||
|
||||
registerWindow(aWindow) {
|
||||
if (!this._observerAdded) {
|
||||
this._observerAdded = true;
|
||||
Services.obs.addObserver(this, "offline-cache-update-completed", true);
|
||||
}
|
||||
let manifestURI = this._getManifestURI(aWindow);
|
||||
this._docManifestSet.add(manifestURI.spec);
|
||||
}
|
||||
@ -95,19 +82,6 @@ class OfflineAppsChild extends ActorChild {
|
||||
this._docIdMap.delete(aMessage.data.docId);
|
||||
}
|
||||
}
|
||||
|
||||
observe(aSubject, aTopic, aState) {
|
||||
if (aTopic == "offline-cache-update-completed") {
|
||||
let cacheUpdate = aSubject.QueryInterface(Ci.nsIOfflineCacheUpdate);
|
||||
let uri = cacheUpdate.manifestURI;
|
||||
if (uri && this._docManifestSet.has(uri.spec)) {
|
||||
this.mm.sendAsyncMessage("OfflineApps:CheckUsage", {
|
||||
uri: uri.spec,
|
||||
principal: E10SUtils.serializePrincipal(cacheUpdate.loadingPrincipal),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OfflineAppsChild.prototype.QueryInterface = ChromeUtils.generateQI([
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "mozilla/CmdLineAndEnvUtils.h"
|
||||
#include "mozilla/XREAppData.h"
|
||||
#include "XREShellData.h"
|
||||
#include "application.ini.h"
|
||||
#include "mozilla/Bootstrap.h"
|
||||
#if defined(XP_WIN)
|
||||
|
495
browser/base/content/aboutDialog-appUpdater-legacy.js
Normal file
495
browser/base/content/aboutDialog-appUpdater-legacy.js
Normal file
@ -0,0 +1,495 @@
|
||||
/* 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/. */
|
||||
|
||||
// Note: this file is included in aboutDialog.xul and preferences/advanced.xul
|
||||
// if MOZ_UPDATER is defined.
|
||||
|
||||
/* import-globals-from aboutDialog.js */
|
||||
|
||||
const PREF_APP_UPDATE_CANCELATIONS_OSX = "app.update.cancelations.osx";
|
||||
const PREF_APP_UPDATE_ELEVATE_NEVER = "app.update.elevate.never";
|
||||
|
||||
function onUnload(aEvent) {
|
||||
if (gAppUpdater) {
|
||||
if (gAppUpdater.isChecking) {
|
||||
gAppUpdater.checker.stopCurrentCheck();
|
||||
}
|
||||
// Safe to call even when there isn't a download in progress.
|
||||
gAppUpdater.removeDownloadListener();
|
||||
gAppUpdater = null;
|
||||
}
|
||||
}
|
||||
|
||||
function appUpdater(options = {}) {
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
"aus",
|
||||
"@mozilla.org/updates/update-service;1",
|
||||
"nsIApplicationUpdateService"
|
||||
);
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
"checker",
|
||||
"@mozilla.org/updates/update-checker;1",
|
||||
"nsIUpdateChecker"
|
||||
);
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
"um",
|
||||
"@mozilla.org/updates/update-manager;1",
|
||||
"nsIUpdateManager"
|
||||
);
|
||||
|
||||
this.options = options;
|
||||
this.updateDeck = document.getElementById("updateDeck");
|
||||
this.promiseAutoUpdateSetting = null;
|
||||
|
||||
this.bundle = Services.strings.createBundle(
|
||||
"chrome://browser/locale/browser.properties"
|
||||
);
|
||||
|
||||
let manualURL = Services.urlFormatter.formatURLPref("app.update.url.manual");
|
||||
let manualLink = document.getElementById("manualLink");
|
||||
manualLink.textContent = manualURL;
|
||||
manualLink.href = manualURL;
|
||||
document.getElementById("failedLink").href = manualURL;
|
||||
|
||||
if (this.updateDisabledByPolicy) {
|
||||
this.selectPanel("policyDisabled");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isReadyForRestart) {
|
||||
this.selectPanel("apply");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.aus.isOtherInstanceHandlingUpdates) {
|
||||
this.selectPanel("otherInstanceHandlingUpdates");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isDownloading) {
|
||||
this.startDownload();
|
||||
// selectPanel("downloading") is called from setupDownloadingUI().
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isStaging) {
|
||||
this.waitForUpdateToStage();
|
||||
// selectPanel("applying"); is called from waitForUpdateToStage().
|
||||
return;
|
||||
}
|
||||
|
||||
// We might need this value later, so start loading it from the disk now.
|
||||
this.promiseAutoUpdateSetting = UpdateUtils.getAppUpdateAutoEnabled();
|
||||
|
||||
// That leaves the options
|
||||
// "Check for updates, but let me choose whether to install them", and
|
||||
// "Automatically install updates".
|
||||
// In both cases, we check for updates without asking.
|
||||
// In the "let me choose" case, we ask before downloading though, in onCheckComplete.
|
||||
this.checkForUpdates();
|
||||
}
|
||||
|
||||
appUpdater.prototype = {
|
||||
// true when there is an update check in progress.
|
||||
isChecking: false,
|
||||
|
||||
// true when there is an update ready to be applied on restart or staged.
|
||||
get isPending() {
|
||||
if (this.update) {
|
||||
return (
|
||||
this.update.state == "pending" ||
|
||||
this.update.state == "pending-service" ||
|
||||
this.update.state == "pending-elevate"
|
||||
);
|
||||
}
|
||||
return (
|
||||
this.um.activeUpdate &&
|
||||
(this.um.activeUpdate.state == "pending" ||
|
||||
this.um.activeUpdate.state == "pending-service" ||
|
||||
this.um.activeUpdate.state == "pending-elevate")
|
||||
);
|
||||
},
|
||||
|
||||
// true when there is an update already staged.
|
||||
get isApplied() {
|
||||
if (this.update) {
|
||||
return (
|
||||
this.update.state == "applied" || this.update.state == "applied-service"
|
||||
);
|
||||
}
|
||||
return (
|
||||
this.um.activeUpdate &&
|
||||
(this.um.activeUpdate.state == "applied" ||
|
||||
this.um.activeUpdate.state == "applied-service")
|
||||
);
|
||||
},
|
||||
|
||||
get isStaging() {
|
||||
if (!this.updateStagingEnabled) {
|
||||
return false;
|
||||
}
|
||||
let errorCode;
|
||||
if (this.update) {
|
||||
errorCode = this.update.errorCode;
|
||||
} else if (this.um.activeUpdate) {
|
||||
errorCode = this.um.activeUpdate.errorCode;
|
||||
}
|
||||
// If the state is pending and the error code is not 0, staging must have
|
||||
// failed.
|
||||
return this.isPending && errorCode == 0;
|
||||
},
|
||||
|
||||
// true when an update ready to restart to finish the update process.
|
||||
get isReadyForRestart() {
|
||||
if (this.updateStagingEnabled) {
|
||||
let errorCode;
|
||||
if (this.update) {
|
||||
errorCode = this.update.errorCode;
|
||||
} else if (this.um.activeUpdate) {
|
||||
errorCode = this.um.activeUpdate.errorCode;
|
||||
}
|
||||
// If the state is pending and the error code is not 0, staging must have
|
||||
// failed and Firefox should be restarted to try to apply the update
|
||||
// without staging.
|
||||
return this.isApplied || (this.isPending && errorCode != 0);
|
||||
}
|
||||
return this.isPending;
|
||||
},
|
||||
|
||||
// true when there is an update download in progress.
|
||||
get isDownloading() {
|
||||
if (this.update) {
|
||||
return this.update.state == "downloading";
|
||||
}
|
||||
return this.um.activeUpdate && this.um.activeUpdate.state == "downloading";
|
||||
},
|
||||
|
||||
// true when updating has been disabled by enterprise policy
|
||||
get updateDisabledByPolicy() {
|
||||
return Services.policies && !Services.policies.isAllowed("appUpdate");
|
||||
},
|
||||
|
||||
// true when updating in background is enabled.
|
||||
get updateStagingEnabled() {
|
||||
return !this.updateDisabledByPolicy && this.aus.canStageUpdates;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the panel of the updateDeck.
|
||||
*
|
||||
* @param aChildID
|
||||
* The id of the deck's child to select, e.g. "apply".
|
||||
*/
|
||||
selectPanel(aChildID) {
|
||||
let panel = document.getElementById(aChildID);
|
||||
|
||||
let button = panel.querySelector("button");
|
||||
if (button) {
|
||||
if (aChildID == "downloadAndInstall") {
|
||||
let updateVersion = gAppUpdater.update.displayVersion;
|
||||
// Include the build ID if this is an "a#" (nightly or aurora) build
|
||||
if (/a\d+$/.test(updateVersion)) {
|
||||
let buildID = gAppUpdater.update.buildID;
|
||||
let year = buildID.slice(0, 4);
|
||||
let month = buildID.slice(4, 6);
|
||||
let day = buildID.slice(6, 8);
|
||||
updateVersion += ` (${year}-${month}-${day})`;
|
||||
}
|
||||
button.label = this.bundle.formatStringFromName(
|
||||
"update.downloadAndInstallButton.label",
|
||||
[updateVersion]
|
||||
);
|
||||
button.accessKey = this.bundle.GetStringFromName(
|
||||
"update.downloadAndInstallButton.accesskey"
|
||||
);
|
||||
}
|
||||
this.updateDeck.selectedPanel = panel;
|
||||
if (
|
||||
this.options.buttonAutoFocus &&
|
||||
(!document.commandDispatcher.focusedElement || // don't steal the focus
|
||||
document.commandDispatcher.focusedElement.localName == "button")
|
||||
) {
|
||||
// except from the other buttons
|
||||
button.focus();
|
||||
}
|
||||
} else {
|
||||
this.updateDeck.selectedPanel = panel;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Check for updates
|
||||
*/
|
||||
checkForUpdates() {
|
||||
// Clear prefs that could prevent a user from discovering available updates.
|
||||
if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_CANCELATIONS_OSX)) {
|
||||
Services.prefs.clearUserPref(PREF_APP_UPDATE_CANCELATIONS_OSX);
|
||||
}
|
||||
if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_ELEVATE_NEVER)) {
|
||||
Services.prefs.clearUserPref(PREF_APP_UPDATE_ELEVATE_NEVER);
|
||||
}
|
||||
this.selectPanel("checkingForUpdates");
|
||||
this.isChecking = true;
|
||||
this.checker.checkForUpdates(this.updateCheckListener, true);
|
||||
// after checking, onCheckComplete() is called
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles oncommand for the "Restart to Update" button
|
||||
* which is presented after the download has been downloaded.
|
||||
*/
|
||||
buttonRestartAfterDownload() {
|
||||
if (!this.isReadyForRestart) {
|
||||
return;
|
||||
}
|
||||
|
||||
gAppUpdater.selectPanel("restarting");
|
||||
|
||||
// Notify all windows that an application quit has been requested.
|
||||
let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].createInstance(
|
||||
Ci.nsISupportsPRBool
|
||||
);
|
||||
Services.obs.notifyObservers(
|
||||
cancelQuit,
|
||||
"quit-application-requested",
|
||||
"restart"
|
||||
);
|
||||
|
||||
// Something aborted the quit process.
|
||||
if (cancelQuit.data) {
|
||||
gAppUpdater.selectPanel("apply");
|
||||
return;
|
||||
}
|
||||
|
||||
// If already in safe mode restart in safe mode (bug 327119)
|
||||
if (Services.appinfo.inSafeMode) {
|
||||
Services.startup.restartInSafeMode(Ci.nsIAppStartup.eAttemptQuit);
|
||||
return;
|
||||
}
|
||||
|
||||
Services.startup.quit(
|
||||
Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Implements nsIUpdateCheckListener. The methods implemented by
|
||||
* nsIUpdateCheckListener are in a different scope from nsIIncrementalDownload
|
||||
* to make it clear which are used by each interface.
|
||||
*/
|
||||
updateCheckListener: {
|
||||
/**
|
||||
* See nsIUpdateService.idl
|
||||
*/
|
||||
onCheckComplete(aRequest, aUpdates) {
|
||||
gAppUpdater.isChecking = false;
|
||||
gAppUpdater.update = gAppUpdater.aus.selectUpdate(aUpdates);
|
||||
if (!gAppUpdater.update) {
|
||||
gAppUpdater.selectPanel("noUpdatesFound");
|
||||
return;
|
||||
}
|
||||
|
||||
if (gAppUpdater.update.unsupported) {
|
||||
if (gAppUpdater.update.detailsURL) {
|
||||
let unsupportedLink = document.getElementById("unsupportedLink");
|
||||
unsupportedLink.href = gAppUpdater.update.detailsURL;
|
||||
}
|
||||
gAppUpdater.selectPanel("unsupportedSystem");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!gAppUpdater.aus.canApplyUpdates) {
|
||||
gAppUpdater.selectPanel("manualUpdate");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!gAppUpdater.promiseAutoUpdateSetting) {
|
||||
gAppUpdater.promiseAutoUpdateSetting = UpdateUtils.getAppUpdateAutoEnabled();
|
||||
}
|
||||
gAppUpdater.promiseAutoUpdateSetting.then(updateAuto => {
|
||||
if (updateAuto) {
|
||||
// automatically download and install
|
||||
gAppUpdater.startDownload();
|
||||
} else {
|
||||
// ask
|
||||
gAppUpdater.selectPanel("downloadAndInstall");
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsIUpdateService.idl
|
||||
*/
|
||||
onError(aRequest, aUpdate) {
|
||||
// Errors in the update check are treated as no updates found. If the
|
||||
// update check fails repeatedly without a success the user will be
|
||||
// notified with the normal app update user interface so this is safe.
|
||||
gAppUpdater.isChecking = false;
|
||||
gAppUpdater.selectPanel("noUpdatesFound");
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsISupports.idl
|
||||
*/
|
||||
QueryInterface: ChromeUtils.generateQI(["nsIUpdateCheckListener"]),
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows the applying UI until the update has finished staging
|
||||
*/
|
||||
waitForUpdateToStage() {
|
||||
if (!this.update) {
|
||||
this.update = this.um.activeUpdate;
|
||||
}
|
||||
this.update.QueryInterface(Ci.nsIWritablePropertyBag);
|
||||
this.update.setProperty("foregroundDownload", "true");
|
||||
this.selectPanel("applying");
|
||||
this.updateUIWhenStagingComplete();
|
||||
},
|
||||
|
||||
/**
|
||||
* Starts the download of an update mar.
|
||||
*/
|
||||
startDownload() {
|
||||
if (!this.update) {
|
||||
this.update = this.um.activeUpdate;
|
||||
}
|
||||
this.update.QueryInterface(Ci.nsIWritablePropertyBag);
|
||||
this.update.setProperty("foregroundDownload", "true");
|
||||
|
||||
let state = this.aus.downloadUpdate(this.update, false);
|
||||
if (state == "failed") {
|
||||
this.selectPanel("downloadFailed");
|
||||
return;
|
||||
}
|
||||
|
||||
this.setupDownloadingUI();
|
||||
},
|
||||
|
||||
/**
|
||||
* Switches to the UI responsible for tracking the download.
|
||||
*/
|
||||
setupDownloadingUI() {
|
||||
this.downloadStatus = document.getElementById("downloadStatus");
|
||||
this.downloadStatus.textContent = DownloadUtils.getTransferTotal(
|
||||
0,
|
||||
this.update.selectedPatch.size
|
||||
);
|
||||
this.selectPanel("downloading");
|
||||
this.aus.addDownloadListener(this);
|
||||
},
|
||||
|
||||
removeDownloadListener() {
|
||||
if (this.aus) {
|
||||
this.aus.removeDownloadListener(this);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsIRequestObserver.idl
|
||||
*/
|
||||
onStartRequest(aRequest) {},
|
||||
|
||||
/**
|
||||
* See nsIRequestObserver.idl
|
||||
*/
|
||||
onStopRequest(aRequest, aStatusCode) {
|
||||
switch (aStatusCode) {
|
||||
case Cr.NS_ERROR_UNEXPECTED:
|
||||
if (
|
||||
this.update.selectedPatch.state == "download-failed" &&
|
||||
(this.update.isCompleteUpdate || this.update.patchCount != 2)
|
||||
) {
|
||||
// Verification error of complete patch, informational text is held in
|
||||
// the update object.
|
||||
this.removeDownloadListener();
|
||||
this.selectPanel("downloadFailed");
|
||||
break;
|
||||
}
|
||||
// Verification failed for a partial patch, complete patch is now
|
||||
// downloading so return early and do NOT remove the download listener!
|
||||
break;
|
||||
case Cr.NS_BINDING_ABORTED:
|
||||
// Do not remove UI listener since the user may resume downloading again.
|
||||
break;
|
||||
case Cr.NS_OK:
|
||||
this.removeDownloadListener();
|
||||
if (this.updateStagingEnabled) {
|
||||
this.selectPanel("applying");
|
||||
this.updateUIWhenStagingComplete();
|
||||
} else {
|
||||
this.selectPanel("apply");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
this.removeDownloadListener();
|
||||
this.selectPanel("downloadFailed");
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsIProgressEventSink.idl
|
||||
*/
|
||||
onStatus(aRequest, aStatus, aStatusArg) {},
|
||||
|
||||
/**
|
||||
* See nsIProgressEventSink.idl
|
||||
*/
|
||||
onProgress(aRequest, aProgress, aProgressMax) {
|
||||
this.downloadStatus.textContent = DownloadUtils.getTransferTotal(
|
||||
aProgress,
|
||||
aProgressMax
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* This function registers an observer that watches for the staging process
|
||||
* to complete. Once it does, it updates the UI to either request that the
|
||||
* user restarts to install the update on success, request that the user
|
||||
* manually download and install the newer version, or automatically download
|
||||
* a complete update if applicable.
|
||||
*/
|
||||
updateUIWhenStagingComplete() {
|
||||
let observer = (aSubject, aTopic, aData) => {
|
||||
// Update the UI when the background updater is finished
|
||||
let status = aData;
|
||||
if (
|
||||
status == "applied" ||
|
||||
status == "applied-service" ||
|
||||
status == "pending" ||
|
||||
status == "pending-service" ||
|
||||
status == "pending-elevate"
|
||||
) {
|
||||
// If the update is successfully applied, or if the updater has
|
||||
// fallen back to non-staged updates, show the "Restart to Update"
|
||||
// button.
|
||||
this.selectPanel("apply");
|
||||
} else if (status == "failed") {
|
||||
// Background update has failed, let's show the UI responsible for
|
||||
// prompting the user to update manually.
|
||||
this.selectPanel("downloadFailed");
|
||||
} else if (status == "downloading") {
|
||||
// We've fallen back to downloading the complete update because the
|
||||
// partial update failed to get staged in the background.
|
||||
// Therefore we need to keep our observer.
|
||||
this.setupDownloadingUI();
|
||||
return;
|
||||
}
|
||||
Services.obs.removeObserver(observer, "update-staged");
|
||||
};
|
||||
Services.obs.addObserver(observer, "update-staged");
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsISupports.idl
|
||||
*/
|
||||
QueryInterface: ChromeUtils.generateQI([
|
||||
"nsIProgressEventSink",
|
||||
"nsIRequestObserver",
|
||||
]),
|
||||
};
|
@ -7,60 +7,53 @@
|
||||
|
||||
/* import-globals-from aboutDialog.js */
|
||||
|
||||
// These two eslint directives should be removed when we remove handling for the
|
||||
// legacy app updater.
|
||||
/* eslint-disable prettier/prettier */
|
||||
/* global AppUpdater, appUpdater, onUnload */
|
||||
|
||||
var { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"DownloadUtils",
|
||||
"resource://gre/modules/DownloadUtils.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"UpdateUtils",
|
||||
"resource://gre/modules/UpdateUtils.jsm"
|
||||
);
|
||||
|
||||
const PREF_APP_UPDATE_CANCELATIONS_OSX = "app.update.cancelations.osx";
|
||||
const PREF_APP_UPDATE_ELEVATE_NEVER = "app.update.elevate.never";
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
DownloadUtils: "resource://gre/modules/DownloadUtils.jsm",
|
||||
UpdateUtils: "resource://gre/modules/UpdateUtils.jsm",
|
||||
});
|
||||
|
||||
var gAppUpdater;
|
||||
|
||||
(() => {
|
||||
|
||||
// If the new app updater is preffed off, load the legacy version.
|
||||
if (!Services.prefs.getBoolPref("browser.aboutDialogNewAppUpdater", false)) {
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://browser/content/aboutDialog-appUpdater-legacy.js",
|
||||
this
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
AppUpdater: "resource:///modules/AppUpdater.jsm",
|
||||
});
|
||||
|
||||
function onUnload(aEvent) {
|
||||
if (gAppUpdater) {
|
||||
if (gAppUpdater.isChecking) {
|
||||
gAppUpdater.checker.stopCurrentCheck();
|
||||
}
|
||||
// Safe to call even when there isn't a download in progress.
|
||||
gAppUpdater.removeDownloadListener();
|
||||
gAppUpdater.stopCurrentCheck();
|
||||
gAppUpdater = null;
|
||||
}
|
||||
}
|
||||
|
||||
function appUpdater(options = {}) {
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
"aus",
|
||||
"@mozilla.org/updates/update-service;1",
|
||||
"nsIApplicationUpdateService"
|
||||
);
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
"checker",
|
||||
"@mozilla.org/updates/update-checker;1",
|
||||
"nsIUpdateChecker"
|
||||
);
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
"um",
|
||||
"@mozilla.org/updates/update-manager;1",
|
||||
"nsIUpdateManager"
|
||||
);
|
||||
this._appUpdater = new AppUpdater();
|
||||
|
||||
this._appUpdateListener = (status, ...args) => {
|
||||
this._onAppUpdateStatus(status, ...args);
|
||||
};
|
||||
this._appUpdater.addListener(this._appUpdateListener);
|
||||
|
||||
this.options = options;
|
||||
this.updateDeck = document.getElementById("updateDeck");
|
||||
this.promiseAutoUpdateSetting = null;
|
||||
|
||||
this.bundle = Services.strings.createBundle(
|
||||
"chrome://browser/locale/browser.properties"
|
||||
@ -72,127 +65,72 @@ function appUpdater(options = {}) {
|
||||
manualLink.href = manualURL;
|
||||
document.getElementById("failedLink").href = manualURL;
|
||||
|
||||
if (this.updateDisabledByPolicy) {
|
||||
this.selectPanel("policyDisabled");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isReadyForRestart) {
|
||||
this.selectPanel("apply");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.aus.isOtherInstanceHandlingUpdates) {
|
||||
this.selectPanel("otherInstanceHandlingUpdates");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isDownloading) {
|
||||
this.startDownload();
|
||||
// selectPanel("downloading") is called from setupDownloadingUI().
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isStaging) {
|
||||
this.waitForUpdateToStage();
|
||||
// selectPanel("applying"); is called from waitForUpdateToStage().
|
||||
return;
|
||||
}
|
||||
|
||||
// We might need this value later, so start loading it from the disk now.
|
||||
this.promiseAutoUpdateSetting = UpdateUtils.getAppUpdateAutoEnabled();
|
||||
|
||||
// That leaves the options
|
||||
// "Check for updates, but let me choose whether to install them", and
|
||||
// "Automatically install updates".
|
||||
// In both cases, we check for updates without asking.
|
||||
// In the "let me choose" case, we ask before downloading though, in onCheckComplete.
|
||||
this.checkForUpdates();
|
||||
this._appUpdater.check();
|
||||
}
|
||||
|
||||
appUpdater.prototype = {
|
||||
// true when there is an update check in progress.
|
||||
isChecking: false,
|
||||
|
||||
// true when there is an update ready to be applied on restart or staged.
|
||||
get isPending() {
|
||||
if (this.update) {
|
||||
return (
|
||||
this.update.state == "pending" ||
|
||||
this.update.state == "pending-service" ||
|
||||
this.update.state == "pending-elevate"
|
||||
);
|
||||
}
|
||||
return (
|
||||
this.um.activeUpdate &&
|
||||
(this.um.activeUpdate.state == "pending" ||
|
||||
this.um.activeUpdate.state == "pending-service" ||
|
||||
this.um.activeUpdate.state == "pending-elevate")
|
||||
);
|
||||
stopCurrentCheck() {
|
||||
this._appUpdater.removeListener(this._appUpdateListener);
|
||||
this._appUpdater.stop();
|
||||
},
|
||||
|
||||
// true when there is an update already staged.
|
||||
get isApplied() {
|
||||
if (this.update) {
|
||||
return (
|
||||
this.update.state == "applied" || this.update.state == "applied-service"
|
||||
);
|
||||
}
|
||||
return (
|
||||
this.um.activeUpdate &&
|
||||
(this.um.activeUpdate.state == "applied" ||
|
||||
this.um.activeUpdate.state == "applied-service")
|
||||
);
|
||||
get update() {
|
||||
return this._appUpdater.update;
|
||||
},
|
||||
|
||||
get isStaging() {
|
||||
if (!this.updateStagingEnabled) {
|
||||
return false;
|
||||
_onAppUpdateStatus(status, ...args) {
|
||||
switch (status) {
|
||||
case AppUpdater.STATUS.UPDATE_DISABLED_BY_POLICY:
|
||||
this.selectPanel("policyDisabled");
|
||||
break;
|
||||
case AppUpdater.STATUS.READY_FOR_RESTART:
|
||||
this.selectPanel("apply");
|
||||
break;
|
||||
case AppUpdater.STATUS.OTHER_INSTANCE_HANDLING_UPDATES:
|
||||
this.selectPanel("otherInstanceHandlingUpdates");
|
||||
break;
|
||||
case AppUpdater.STATUS.DOWNLOADING:
|
||||
if (!args.length) {
|
||||
this.downloadStatus = document.getElementById("downloadStatus");
|
||||
this.downloadStatus.textContent = DownloadUtils.getTransferTotal(
|
||||
0,
|
||||
this.update.selectedPatch.size
|
||||
);
|
||||
this.selectPanel("downloading");
|
||||
} else {
|
||||
let [progress, max] = args;
|
||||
this.downloadStatus.textContent = DownloadUtils.getTransferTotal(
|
||||
progress,
|
||||
max
|
||||
);
|
||||
}
|
||||
break;
|
||||
case AppUpdater.STATUS.STAGING:
|
||||
this.selectPanel("applying");
|
||||
break;
|
||||
case AppUpdater.STATUS.CHECKING:
|
||||
this.selectPanel("checkingForUpdates");
|
||||
break;
|
||||
case AppUpdater.STATUS.NO_UPDATES_FOUND:
|
||||
this.selectPanel("noUpdatesFound");
|
||||
break;
|
||||
case AppUpdater.STATUS.UNSUPPORTED_SYSTEM:
|
||||
if (this.update.detailsURL) {
|
||||
let unsupportedLink = document.getElementById("unsupportedLink");
|
||||
unsupportedLink.href = this.update.detailsURL;
|
||||
}
|
||||
this.selectPanel("unsupportedSystem");
|
||||
break;
|
||||
case AppUpdater.STATUS.MANUAL_UPDATE:
|
||||
this.selectPanel("manualUpdate");
|
||||
break;
|
||||
case AppUpdater.STATUS.DOWNLOAD_AND_INSTALL:
|
||||
this.selectPanel("downloadAndInstall");
|
||||
break;
|
||||
case AppUpdater.STATUS.DOWNLOAD_FAILED:
|
||||
this.selectPanel("downloadFailed");
|
||||
break;
|
||||
}
|
||||
let errorCode;
|
||||
if (this.update) {
|
||||
errorCode = this.update.errorCode;
|
||||
} else if (this.um.activeUpdate) {
|
||||
errorCode = this.um.activeUpdate.errorCode;
|
||||
}
|
||||
// If the state is pending and the error code is not 0, staging must have
|
||||
// failed.
|
||||
return this.isPending && errorCode == 0;
|
||||
},
|
||||
|
||||
// true when an update ready to restart to finish the update process.
|
||||
get isReadyForRestart() {
|
||||
if (this.updateStagingEnabled) {
|
||||
let errorCode;
|
||||
if (this.update) {
|
||||
errorCode = this.update.errorCode;
|
||||
} else if (this.um.activeUpdate) {
|
||||
errorCode = this.um.activeUpdate.errorCode;
|
||||
}
|
||||
// If the state is pending and the error code is not 0, staging must have
|
||||
// failed and Firefox should be restarted to try to apply the update
|
||||
// without staging.
|
||||
return this.isApplied || (this.isPending && errorCode != 0);
|
||||
}
|
||||
return this.isPending;
|
||||
},
|
||||
|
||||
// true when there is an update download in progress.
|
||||
get isDownloading() {
|
||||
if (this.update) {
|
||||
return this.update.state == "downloading";
|
||||
}
|
||||
return this.um.activeUpdate && this.um.activeUpdate.state == "downloading";
|
||||
},
|
||||
|
||||
// true when updating has been disabled by enterprise policy
|
||||
get updateDisabledByPolicy() {
|
||||
return Services.policies && !Services.policies.isAllowed("appUpdate");
|
||||
},
|
||||
|
||||
// true when updating in background is enabled.
|
||||
get updateStagingEnabled() {
|
||||
return !this.updateDisabledByPolicy && this.aus.canStageUpdates;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -242,17 +180,7 @@ appUpdater.prototype = {
|
||||
* Check for updates
|
||||
*/
|
||||
checkForUpdates() {
|
||||
// Clear prefs that could prevent a user from discovering available updates.
|
||||
if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_CANCELATIONS_OSX)) {
|
||||
Services.prefs.clearUserPref(PREF_APP_UPDATE_CANCELATIONS_OSX);
|
||||
}
|
||||
if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_ELEVATE_NEVER)) {
|
||||
Services.prefs.clearUserPref(PREF_APP_UPDATE_ELEVATE_NEVER);
|
||||
}
|
||||
this.selectPanel("checkingForUpdates");
|
||||
this.isChecking = true;
|
||||
this.checker.checkForUpdates(this.updateCheckListener, true);
|
||||
// after checking, onCheckComplete() is called
|
||||
this._appUpdater.checkForUpdates();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -260,7 +188,7 @@ appUpdater.prototype = {
|
||||
* which is presented after the download has been downloaded.
|
||||
*/
|
||||
buttonRestartAfterDownload() {
|
||||
if (!this.isReadyForRestart) {
|
||||
if (!this._appUpdater.isReadyForRestart) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -293,223 +221,15 @@ appUpdater.prototype = {
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Implements nsIUpdateCheckListener. The methods implemented by
|
||||
* nsIUpdateCheckListener are in a different scope from nsIIncrementalDownload
|
||||
* to make it clear which are used by each interface.
|
||||
*/
|
||||
updateCheckListener: {
|
||||
/**
|
||||
* See nsIUpdateService.idl
|
||||
*/
|
||||
onCheckComplete(aRequest, aUpdates, aUpdateCount) {
|
||||
gAppUpdater.isChecking = false;
|
||||
gAppUpdater.update = gAppUpdater.aus.selectUpdate(
|
||||
aUpdates,
|
||||
aUpdates.length
|
||||
);
|
||||
if (!gAppUpdater.update) {
|
||||
gAppUpdater.selectPanel("noUpdatesFound");
|
||||
return;
|
||||
}
|
||||
|
||||
if (gAppUpdater.update.unsupported) {
|
||||
if (gAppUpdater.update.detailsURL) {
|
||||
let unsupportedLink = document.getElementById("unsupportedLink");
|
||||
unsupportedLink.href = gAppUpdater.update.detailsURL;
|
||||
}
|
||||
gAppUpdater.selectPanel("unsupportedSystem");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!gAppUpdater.aus.canApplyUpdates) {
|
||||
gAppUpdater.selectPanel("manualUpdate");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!gAppUpdater.promiseAutoUpdateSetting) {
|
||||
gAppUpdater.promiseAutoUpdateSetting = UpdateUtils.getAppUpdateAutoEnabled();
|
||||
}
|
||||
gAppUpdater.promiseAutoUpdateSetting.then(updateAuto => {
|
||||
if (updateAuto) {
|
||||
// automatically download and install
|
||||
gAppUpdater.startDownload();
|
||||
} else {
|
||||
// ask
|
||||
gAppUpdater.selectPanel("downloadAndInstall");
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsIUpdateService.idl
|
||||
*/
|
||||
onError(aRequest, aUpdate) {
|
||||
// Errors in the update check are treated as no updates found. If the
|
||||
// update check fails repeatedly without a success the user will be
|
||||
// notified with the normal app update user interface so this is safe.
|
||||
gAppUpdater.isChecking = false;
|
||||
gAppUpdater.selectPanel("noUpdatesFound");
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsISupports.idl
|
||||
*/
|
||||
QueryInterface: ChromeUtils.generateQI(["nsIUpdateCheckListener"]),
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows the applying UI until the update has finished staging
|
||||
*/
|
||||
waitForUpdateToStage() {
|
||||
if (!this.update) {
|
||||
this.update = this.um.activeUpdate;
|
||||
}
|
||||
this.update.QueryInterface(Ci.nsIWritablePropertyBag);
|
||||
this.update.setProperty("foregroundDownload", "true");
|
||||
this.selectPanel("applying");
|
||||
this.updateUIWhenStagingComplete();
|
||||
},
|
||||
|
||||
/**
|
||||
* Starts the download of an update mar.
|
||||
*/
|
||||
startDownload() {
|
||||
if (!this.update) {
|
||||
this.update = this.um.activeUpdate;
|
||||
}
|
||||
this.update.QueryInterface(Ci.nsIWritablePropertyBag);
|
||||
this.update.setProperty("foregroundDownload", "true");
|
||||
|
||||
let state = this.aus.downloadUpdate(this.update, false);
|
||||
if (state == "failed") {
|
||||
this.selectPanel("downloadFailed");
|
||||
return;
|
||||
}
|
||||
|
||||
this.setupDownloadingUI();
|
||||
this._appUpdater.startDownload();
|
||||
},
|
||||
|
||||
/**
|
||||
* Switches to the UI responsible for tracking the download.
|
||||
*/
|
||||
setupDownloadingUI() {
|
||||
this.downloadStatus = document.getElementById("downloadStatus");
|
||||
this.downloadStatus.textContent = DownloadUtils.getTransferTotal(
|
||||
0,
|
||||
this.update.selectedPatch.size
|
||||
);
|
||||
this.selectPanel("downloading");
|
||||
this.aus.addDownloadListener(this);
|
||||
},
|
||||
|
||||
removeDownloadListener() {
|
||||
if (this.aus) {
|
||||
this.aus.removeDownloadListener(this);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsIRequestObserver.idl
|
||||
*/
|
||||
onStartRequest(aRequest) {},
|
||||
|
||||
/**
|
||||
* See nsIRequestObserver.idl
|
||||
*/
|
||||
onStopRequest(aRequest, aStatusCode) {
|
||||
switch (aStatusCode) {
|
||||
case Cr.NS_ERROR_UNEXPECTED:
|
||||
if (
|
||||
this.update.selectedPatch.state == "download-failed" &&
|
||||
(this.update.isCompleteUpdate || this.update.patchCount != 2)
|
||||
) {
|
||||
// Verification error of complete patch, informational text is held in
|
||||
// the update object.
|
||||
this.removeDownloadListener();
|
||||
this.selectPanel("downloadFailed");
|
||||
break;
|
||||
}
|
||||
// Verification failed for a partial patch, complete patch is now
|
||||
// downloading so return early and do NOT remove the download listener!
|
||||
break;
|
||||
case Cr.NS_BINDING_ABORTED:
|
||||
// Do not remove UI listener since the user may resume downloading again.
|
||||
break;
|
||||
case Cr.NS_OK:
|
||||
this.removeDownloadListener();
|
||||
if (this.updateStagingEnabled) {
|
||||
this.selectPanel("applying");
|
||||
this.updateUIWhenStagingComplete();
|
||||
} else {
|
||||
this.selectPanel("apply");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
this.removeDownloadListener();
|
||||
this.selectPanel("downloadFailed");
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsIProgressEventSink.idl
|
||||
*/
|
||||
onStatus(aRequest, aContext, aStatus, aStatusArg) {},
|
||||
|
||||
/**
|
||||
* See nsIProgressEventSink.idl
|
||||
*/
|
||||
onProgress(aRequest, aContext, aProgress, aProgressMax) {
|
||||
this.downloadStatus.textContent = DownloadUtils.getTransferTotal(
|
||||
aProgress,
|
||||
aProgressMax
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* This function registers an observer that watches for the staging process
|
||||
* to complete. Once it does, it updates the UI to either request that the
|
||||
* user restarts to install the update on success, request that the user
|
||||
* manually download and install the newer version, or automatically download
|
||||
* a complete update if applicable.
|
||||
*/
|
||||
updateUIWhenStagingComplete() {
|
||||
let observer = (aSubject, aTopic, aData) => {
|
||||
// Update the UI when the background updater is finished
|
||||
let status = aData;
|
||||
if (
|
||||
status == "applied" ||
|
||||
status == "applied-service" ||
|
||||
status == "pending" ||
|
||||
status == "pending-service" ||
|
||||
status == "pending-elevate"
|
||||
) {
|
||||
// If the update is successfully applied, or if the updater has
|
||||
// fallen back to non-staged updates, show the "Restart to Update"
|
||||
// button.
|
||||
this.selectPanel("apply");
|
||||
} else if (status == "failed") {
|
||||
// Background update has failed, let's show the UI responsible for
|
||||
// prompting the user to update manually.
|
||||
this.selectPanel("downloadFailed");
|
||||
} else if (status == "downloading") {
|
||||
// We've fallen back to downloading the complete update because the
|
||||
// partial update failed to get staged in the background.
|
||||
// Therefore we need to keep our observer.
|
||||
this.setupDownloadingUI();
|
||||
return;
|
||||
}
|
||||
Services.obs.removeObserver(observer, "update-staged");
|
||||
};
|
||||
Services.obs.addObserver(observer, "update-staged");
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsISupports.idl
|
||||
*/
|
||||
QueryInterface: ChromeUtils.generateQI([
|
||||
"nsIProgressEventSink",
|
||||
"nsIRequestObserver",
|
||||
]),
|
||||
};
|
||||
|
||||
this.onUnload = onUnload;
|
||||
this.appUpdater = appUpdater;
|
||||
|
||||
})();
|
||||
|
@ -599,10 +599,9 @@ var gIdentityHandler = {
|
||||
*/
|
||||
_hasCustomRoot() {
|
||||
let issuerCert = null;
|
||||
// Walk the whole chain to get the last cert.
|
||||
// eslint-disable-next-line no-empty
|
||||
for (issuerCert of this._secInfo.succeededCertChain.getEnumerator()) {
|
||||
}
|
||||
issuerCert = this._secInfo.succeededCertChain[
|
||||
this._secInfo.succeededCertChain.length - 1
|
||||
];
|
||||
|
||||
return !issuerCert.isBuiltInRoot;
|
||||
},
|
||||
|
@ -1911,10 +1911,6 @@ var gBrowserInit = {
|
||||
// until all of its dependencies are handled.
|
||||
Services.appShell.hiddenDOMWindow;
|
||||
|
||||
// We need to set the OfflineApps message listeners up before we
|
||||
// load homepages, which might need them.
|
||||
OfflineApps.init();
|
||||
|
||||
gBrowser.addEventListener(
|
||||
"InsecureLoginFormsStateChange",
|
||||
function() {
|
||||
@ -4109,20 +4105,10 @@ function getDetailedCertErrorInfo(location, securityInfo) {
|
||||
return certErrorDetails;
|
||||
}
|
||||
|
||||
// TODO: can we pull getDERString and getPEMString in from pippki.js instead of
|
||||
// TODO: can we pull getPEMString in from pippki.js instead of
|
||||
// duplicating them here?
|
||||
function getDERString(cert) {
|
||||
var length = {};
|
||||
var derArray = cert.getRawDER(length);
|
||||
var derString = "";
|
||||
for (var i = 0; i < derArray.length; i++) {
|
||||
derString += String.fromCharCode(derArray[i]);
|
||||
}
|
||||
return derString;
|
||||
}
|
||||
|
||||
function getPEMString(cert) {
|
||||
var derb64 = btoa(getDERString(cert));
|
||||
var derb64 = cert.getBase64DERString();
|
||||
// Wrap the Base64 string into lines of 64 characters,
|
||||
// with CRLF line breaks (as specified in RFC 1421).
|
||||
var wrapped = derb64.replace(/(\S{64}(?!$))/g, "$1\r\n");
|
||||
@ -8083,115 +8069,6 @@ var BrowserOffline = {
|
||||
},
|
||||
};
|
||||
|
||||
var OfflineApps = {
|
||||
warnUsage(browser, principal, host) {
|
||||
if (!browser) {
|
||||
return;
|
||||
}
|
||||
|
||||
let mainAction = {
|
||||
label: gNavigatorBundle.getString("offlineApps.manageUsage"),
|
||||
accessKey: gNavigatorBundle.getString("offlineApps.manageUsageAccessKey"),
|
||||
callback: this.manage,
|
||||
};
|
||||
|
||||
let warnQuotaKB = Services.prefs.getIntPref("offline-apps.quota.warn");
|
||||
// This message shows the quota in MB, and so we divide the quota (in kb) by 1024.
|
||||
let message = gNavigatorBundle.getFormattedString("offlineApps.usage", [
|
||||
host,
|
||||
warnQuotaKB / 1024,
|
||||
]);
|
||||
|
||||
let anchorID = "indexedDB-notification-icon";
|
||||
let options = {
|
||||
persistent: true,
|
||||
hideClose: true,
|
||||
};
|
||||
PopupNotifications.show(
|
||||
browser,
|
||||
"offline-app-usage",
|
||||
message,
|
||||
anchorID,
|
||||
mainAction,
|
||||
null,
|
||||
options
|
||||
);
|
||||
|
||||
// Now that we've warned once, prevent the warning from showing up
|
||||
// again.
|
||||
Services.perms.addFromPrincipal(
|
||||
principal,
|
||||
"offline-app",
|
||||
Ci.nsIOfflineCacheUpdateService.ALLOW_NO_WARN
|
||||
);
|
||||
},
|
||||
|
||||
// XXX: duplicated in preferences/advanced.js
|
||||
_getOfflineAppUsage(host, groups) {
|
||||
let cacheService = Cc[
|
||||
"@mozilla.org/network/application-cache-service;1"
|
||||
].getService(Ci.nsIApplicationCacheService);
|
||||
if (!groups) {
|
||||
try {
|
||||
groups = cacheService.getGroups();
|
||||
} catch (ex) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
let usage = 0;
|
||||
for (let group of groups) {
|
||||
let uri = Services.io.newURI(group);
|
||||
if (uri.asciiHost == host) {
|
||||
let cache = cacheService.getActiveCache(group);
|
||||
usage += cache.usage;
|
||||
}
|
||||
}
|
||||
|
||||
return usage;
|
||||
},
|
||||
|
||||
_usedMoreThanWarnQuota(principal, asciiHost) {
|
||||
// if the user has already allowed excessive usage, don't bother checking
|
||||
if (
|
||||
Services.perms.testExactPermissionFromPrincipal(
|
||||
principal,
|
||||
"offline-app"
|
||||
) != Ci.nsIOfflineCacheUpdateService.ALLOW_NO_WARN
|
||||
) {
|
||||
let usageBytes = this._getOfflineAppUsage(asciiHost);
|
||||
let warnQuotaKB = Services.prefs.getIntPref("offline-apps.quota.warn");
|
||||
// The pref is in kb, the usage we get is in bytes, so multiply the quota
|
||||
// to compare correctly:
|
||||
if (usageBytes >= warnQuotaKB * 1024) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
manage() {
|
||||
openPreferences("panePrivacy");
|
||||
},
|
||||
|
||||
receiveMessage(msg) {
|
||||
if (msg.name !== "OfflineApps:CheckUsage") {
|
||||
return;
|
||||
}
|
||||
let uri = makeURI(msg.data.uri);
|
||||
let principal = E10SUtils.deserializePrincipal(msg.data.principal);
|
||||
if (this._usedMoreThanWarnQuota(principal, uri.asciiHost)) {
|
||||
this.warnUsage(msg.target, principal, uri.host);
|
||||
}
|
||||
},
|
||||
|
||||
init() {
|
||||
let mm = window.messageManager;
|
||||
mm.addMessageListener("OfflineApps:CheckUsage", this);
|
||||
},
|
||||
};
|
||||
|
||||
var IndexedDBPromptHelper = {
|
||||
_permissionsPrompt: "indexedDB-permissions-prompt",
|
||||
_permissionsResponse: "indexedDB-permissions-response",
|
||||
|
@ -63,13 +63,14 @@ function openContextMenu(aMessage) {
|
||||
makeURI(data.baseURI)
|
||||
);
|
||||
|
||||
if (frameReferrerInfo) {
|
||||
frameReferrerInfo =
|
||||
E10SUtils.deserializeReferrerInfo(frameReferrerInfo);
|
||||
}
|
||||
|
||||
if (linkReferrerInfo && data.isRemote) {
|
||||
linkReferrerInfo = E10SUtils.deserializeReferrerInfo(linkReferrerInfo);
|
||||
if (data.isRemote) {
|
||||
if (frameReferrerInfo) {
|
||||
frameReferrerInfo =
|
||||
E10SUtils.deserializeReferrerInfo(frameReferrerInfo);
|
||||
}
|
||||
if (linkReferrerInfo) {
|
||||
linkReferrerInfo = E10SUtils.deserializeReferrerInfo(linkReferrerInfo);
|
||||
}
|
||||
}
|
||||
|
||||
gContextMenuContentData = {
|
||||
|
@ -16,24 +16,14 @@ function getSecurityInfo(securityInfoAsString) {
|
||||
function getCertChain(securityInfoAsString) {
|
||||
let certChain = "";
|
||||
let securityInfo = getSecurityInfo(securityInfoAsString);
|
||||
for (let cert of securityInfo.failedCertChain.getEnumerator()) {
|
||||
for (let cert of securityInfo.failedCertChain) {
|
||||
certChain += getPEMString(cert);
|
||||
}
|
||||
return certChain;
|
||||
}
|
||||
|
||||
function getDERString(cert) {
|
||||
var length = {};
|
||||
var derArray = cert.getRawDER(length);
|
||||
var derString = "";
|
||||
for (var i = 0; i < derArray.length; i++) {
|
||||
derString += String.fromCharCode(derArray[i]);
|
||||
}
|
||||
return derString;
|
||||
}
|
||||
|
||||
function getPEMString(cert) {
|
||||
var derb64 = btoa(getDERString(cert));
|
||||
var derb64 = cert.getBase64DERString();
|
||||
// Wrap the Base64 string into lines of 64 characters,
|
||||
// with CRLF line breaks (as specified in RFC 1421).
|
||||
var wrapped = derb64.replace(/(\S{64}(?!$))/g, "$1\r\n");
|
||||
|
@ -0,0 +1,40 @@
|
||||
<!doctype html>
|
||||
<html class="wait">
|
||||
<meta charset="utf-8">
|
||||
<title>currentSrc is right even if underlying image is a shared blob</title>
|
||||
<img id="first">
|
||||
<img id="second">
|
||||
<script>
|
||||
(async function() {
|
||||
let canvas = document.createElement("canvas");
|
||||
canvas.width = 100;
|
||||
canvas.height = 100;
|
||||
let ctx = canvas.getContext("2d");
|
||||
ctx.fillStyle = "green";
|
||||
ctx.rect(0, 0, 100, 100);
|
||||
ctx.fill();
|
||||
|
||||
let blob = await new Promise(resolve => canvas.toBlob(resolve));
|
||||
|
||||
let first = document.querySelector("#first");
|
||||
let second = document.querySelector("#second");
|
||||
|
||||
let firstLoad = new Promise(resolve => {
|
||||
first.addEventListener("load", resolve, { once: true });
|
||||
});
|
||||
|
||||
let secondLoad = new Promise(resolve => {
|
||||
second.addEventListener("load", resolve, { once: true });
|
||||
});
|
||||
|
||||
let uri1 = URL.createObjectURL(blob);
|
||||
let uri2 = URL.createObjectURL(blob);
|
||||
first.src = uri1;
|
||||
second.src = uri2;
|
||||
|
||||
await firstLoad;
|
||||
await secondLoad;
|
||||
URL.revokeObjectURL(uri1);
|
||||
document.documentElement.className = "";
|
||||
}());
|
||||
</script>
|
@ -6,7 +6,6 @@
|
||||
###############################################################################
|
||||
|
||||
[DEFAULT]
|
||||
prefs = browser.cache.offline.insecure.enable=true
|
||||
support-files =
|
||||
alltabslistener.html
|
||||
app_bug575561.html
|
||||
@ -292,14 +291,6 @@ tags = clipboard
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_new_http_window_opened_from_file_tab.js]
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_offlineQuotaNotification.js]
|
||||
support-files = offlineQuotaNotification.cacheManifest offlineQuotaNotification.html
|
||||
skip-if = true # Bug 1579444
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_gZipOfflineChild.js]
|
||||
skip-if = true # Bug 1579444
|
||||
support-files = test_offline_gzip.html gZipOfflineChild.cacheManifest gZipOfflineChild.cacheManifest^headers^ gZipOfflineChild.html gZipOfflineChild.html^headers^
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_page_style_menu.js]
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_page_style_menu_update.js]
|
||||
|
@ -1,92 +0,0 @@
|
||||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
const URL =
|
||||
"http://mochi.test:8888/browser/browser/base/content/test/general/test_offline_gzip.html";
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
// Clean up after ourself
|
||||
let uri = Services.io.newURI(URL);
|
||||
let principal = Services.scriptSecurityManager.createCodebasePrincipal(
|
||||
uri,
|
||||
{}
|
||||
);
|
||||
Services.perms.removeFromPrincipal(principal, "offline-app");
|
||||
});
|
||||
|
||||
//
|
||||
// Handle "message" events which are posted from the iframe upon
|
||||
// offline cache events.
|
||||
//
|
||||
function contentTask() {
|
||||
const { clearInterval, setInterval } = ChromeUtils.import(
|
||||
"resource://gre/modules/Timer.jsm"
|
||||
);
|
||||
|
||||
let resolve;
|
||||
let promise = new Promise(r => {
|
||||
resolve = r;
|
||||
});
|
||||
|
||||
var cacheCount = 0;
|
||||
var intervalID = 0;
|
||||
|
||||
function handleMessageEvents(event) {
|
||||
cacheCount++;
|
||||
switch (cacheCount) {
|
||||
case 1:
|
||||
// This is the initial caching off offline data.
|
||||
is(event.data, "oncache", "Child was successfully cached.");
|
||||
// Reload the frame; this will generate an error message
|
||||
// in the case of bug 501422.
|
||||
event.source.location.reload();
|
||||
// Use setInterval to repeatedly call a function which
|
||||
// checks that one of two things has occurred: either
|
||||
// the offline cache is udpated (which means our iframe
|
||||
// successfully reloaded), or the string "error" appears
|
||||
// in the iframe, as in the case of bug 501422.
|
||||
intervalID = setInterval(function() {
|
||||
// Sometimes document.body may not exist, and trying to access
|
||||
// it will throw an exception, so handle this case.
|
||||
try {
|
||||
var bodyInnerHTML = event.source.document.body.innerHTML;
|
||||
} catch (e) {
|
||||
bodyInnerHTML = "";
|
||||
}
|
||||
if (cacheCount == 2 || bodyInnerHTML.includes("error")) {
|
||||
clearInterval(intervalID);
|
||||
is(cacheCount, 2, "frame not reloaded successfully");
|
||||
if (cacheCount != 2) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}, 100);
|
||||
break;
|
||||
case 2:
|
||||
is(event.data, "onupdate", "Child was successfully updated.");
|
||||
clearInterval(intervalID);
|
||||
resolve();
|
||||
break;
|
||||
default:
|
||||
// how'd we get here?
|
||||
ok(false, "cacheCount not 1 or 2");
|
||||
}
|
||||
}
|
||||
|
||||
content.addEventListener("message", handleMessageEvents);
|
||||
return promise;
|
||||
}
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
// Open a new tab.
|
||||
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, URL);
|
||||
registerCleanupFunction(() => gBrowser.removeCurrentTab());
|
||||
|
||||
BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser).then(() => {
|
||||
ContentTask.spawn(gBrowser.selectedBrowser, null, contentTask).then(finish);
|
||||
});
|
||||
}
|
@ -1,106 +0,0 @@
|
||||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
// Test offline quota warnings - must be run as a mochitest-browser test or
|
||||
// else the test runner gets in the way of notifications due to bug 857897.
|
||||
|
||||
const URL =
|
||||
"http://mochi.test:8888/browser/browser/base/content/test/general/offlineQuotaNotification.html";
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
// Clean up after ourself
|
||||
let uri = Services.io.newURI(URL);
|
||||
let principal = Services.scriptSecurityManager.createCodebasePrincipal(
|
||||
uri,
|
||||
{}
|
||||
);
|
||||
Services.perms.removeFromPrincipal(principal, "offline-app");
|
||||
Services.prefs.clearUserPref("offline-apps.quota.warn");
|
||||
let { OfflineAppCacheHelper } = ChromeUtils.import(
|
||||
"resource://gre/modules/offlineAppCache.jsm"
|
||||
);
|
||||
OfflineAppCacheHelper.clear();
|
||||
});
|
||||
|
||||
// Same as the other one, but for in-content preferences
|
||||
function checkInContentPreferences(win) {
|
||||
let doc = win.document;
|
||||
let sel = doc.getElementById("categories").selectedItems[0].id;
|
||||
is(
|
||||
gBrowser.currentURI.spec,
|
||||
"about:preferences#privacy",
|
||||
"about:preferences loaded"
|
||||
);
|
||||
is(sel, "category-privacy", "Privacy pane was selected");
|
||||
// all good, we are done.
|
||||
win.close();
|
||||
finish();
|
||||
}
|
||||
|
||||
async function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let notificationShown = promiseNotification();
|
||||
|
||||
// Open a new tab.
|
||||
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, URL);
|
||||
registerCleanupFunction(() => gBrowser.removeCurrentTab());
|
||||
|
||||
// Wait for the tab to load.
|
||||
await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
info("Loaded page, adding onCached handler");
|
||||
// Need a promise to keep track of when we've added our handler.
|
||||
let mm = gBrowser.selectedBrowser.messageManager;
|
||||
let onCachedAttached = BrowserTestUtils.waitForMessage(
|
||||
mm,
|
||||
"Test:OnCachedAttached"
|
||||
);
|
||||
let gotCached = ContentTask.spawn(
|
||||
gBrowser.selectedBrowser,
|
||||
null,
|
||||
async function() {
|
||||
return new Promise(resolve => {
|
||||
content.window.applicationCache.oncached = function() {
|
||||
setTimeout(resolve, 0);
|
||||
};
|
||||
sendAsyncMessage("Test:OnCachedAttached");
|
||||
});
|
||||
}
|
||||
);
|
||||
gotCached.then(async function() {
|
||||
// We got cached - now we should have provoked the quota warning.
|
||||
await notificationShown;
|
||||
let notification = PopupNotifications.getNotification("offline-app-usage");
|
||||
ok(notification, "have offline-app-usage notification");
|
||||
// select the default action - this should cause the preferences
|
||||
// tab to open - which we track via an "Initialized" event.
|
||||
PopupNotifications.panel.firstElementChild.button.click();
|
||||
let newTabBrowser = gBrowser.getBrowserForTab(gBrowser.selectedTab);
|
||||
newTabBrowser.addEventListener(
|
||||
"Initialized",
|
||||
function() {
|
||||
executeSoon(function() {
|
||||
checkInContentPreferences(newTabBrowser.contentWindow);
|
||||
});
|
||||
},
|
||||
{ capture: true, once: true }
|
||||
);
|
||||
});
|
||||
onCachedAttached.then(function() {
|
||||
Services.prefs.setIntPref("offline-apps.quota.warn", 1);
|
||||
});
|
||||
}
|
||||
|
||||
function promiseNotification() {
|
||||
return new Promise(resolve => {
|
||||
PopupNotifications.panel.addEventListener(
|
||||
"popupshown",
|
||||
function() {
|
||||
resolve();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
});
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
CACHE MANIFEST
|
||||
gZipOfflineChild.html
|
@ -1 +0,0 @@
|
||||
Content-Type: text/cache-manifest
|
Binary file not shown.
@ -1,2 +0,0 @@
|
||||
Content-Type: text/html
|
||||
Content-Encoding: gzip
|
@ -1,7 +0,0 @@
|
||||
CACHE MANIFEST
|
||||
# Any copyright is dedicated to the Public Domain.
|
||||
# http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
# store a "large" file so an "over quota warning" will be issued - any file
|
||||
# larger than 1kb and in '_BROWSER_FILES' should be right...
|
||||
title_test.svg
|
@ -1,9 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html manifest="offlineQuotaNotification.cacheManifest">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test offline app quota notification</title>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
</head>
|
||||
</html>
|
@ -1,21 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=501422
|
||||
|
||||
When content which was transported over the network with
|
||||
Content-Type: gzip is added to the offline
|
||||
cache, it can be fetched from the cache successfully.
|
||||
-->
|
||||
<head>
|
||||
<title>Test gzipped offline resources</title>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
<p id="display">
|
||||
<iframe name="testFrame" src="gZipOfflineChild.html"></iframe>
|
||||
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -3,6 +3,9 @@ support-files=
|
||||
head.js
|
||||
dummy.js
|
||||
dummy_page.html
|
||||
prefs=
|
||||
browser.cache.offline.enable=true
|
||||
browser.cache.offline.storage.enable=true
|
||||
|
||||
[browser_purgehistory_clears_sh.js]
|
||||
[browser_sanitize-formhistory.js]
|
||||
|
@ -5,7 +5,7 @@ const { SiteDataTestUtils } = ChromeUtils.import(
|
||||
|
||||
// 2 domains: www.mozilla.org (session-only) mozilla.org (allowed) - after the
|
||||
// cleanp, mozilla.org must have data.
|
||||
add_task(async function subDomains() {
|
||||
add_task(async function subDomains1() {
|
||||
info("Test subdomains and custom setting");
|
||||
|
||||
// Let's clean up all the data.
|
||||
@ -21,81 +21,64 @@ add_task(async function subDomains() {
|
||||
});
|
||||
|
||||
// Domains and data
|
||||
let uriA = Services.io.newURI("https://www.mozilla.org");
|
||||
let originA = "https://www.mozilla.org";
|
||||
PermissionTestUtils.add(
|
||||
uriA,
|
||||
originA,
|
||||
"cookie",
|
||||
Ci.nsICookiePermission.ACCESS_SESSION
|
||||
);
|
||||
|
||||
Services.cookies.add(
|
||||
uriA.host,
|
||||
"/test",
|
||||
"a",
|
||||
"b",
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
Date.now() + 24000 * 60 * 60,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET
|
||||
SiteDataTestUtils.addToCookies(originA);
|
||||
await SiteDataTestUtils.addToIndexedDB(originA);
|
||||
|
||||
let originB = "https://mozilla.org";
|
||||
PermissionTestUtils.add(
|
||||
originB,
|
||||
"cookie",
|
||||
Ci.nsICookiePermission.ACCESS_ALLOW
|
||||
);
|
||||
|
||||
await createIndexedDB(uriA.host, {});
|
||||
|
||||
let uriB = Services.io.newURI("https://mozilla.org");
|
||||
PermissionTestUtils.add(uriB, "cookie", Ci.nsICookiePermission.ACCESS_ALLOW);
|
||||
|
||||
Services.cookies.add(
|
||||
uriB.host,
|
||||
"/test",
|
||||
"c",
|
||||
"d",
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
Date.now() + 24000 * 60 * 60,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET
|
||||
);
|
||||
|
||||
await createIndexedDB(uriB.host, {});
|
||||
SiteDataTestUtils.addToCookies(originB);
|
||||
await SiteDataTestUtils.addToIndexedDB(originB);
|
||||
|
||||
// Check
|
||||
ok(await checkCookie(uriA.host, {}), "We have cookies for URI: " + uriA.host);
|
||||
ok(await checkIndexedDB(uriA.host, {}), "We have IDB for URI: " + uriA.host);
|
||||
ok(await checkCookie(uriB.host, {}), "We have cookies for URI: " + uriB.host);
|
||||
ok(await checkIndexedDB(uriB.host, {}), "We have IDB for URI: " + uriB.host);
|
||||
ok(SiteDataTestUtils.hasCookies(originA), "We have cookies for " + originA);
|
||||
ok(
|
||||
await SiteDataTestUtils.hasIndexedDB(originA),
|
||||
"We have IDB for " + originA
|
||||
);
|
||||
ok(SiteDataTestUtils.hasCookies(originB), "We have cookies for " + originB);
|
||||
ok(
|
||||
await SiteDataTestUtils.hasIndexedDB(originB),
|
||||
"We have IDB for " + originB
|
||||
);
|
||||
|
||||
// Cleaning up
|
||||
await Sanitizer.runSanitizeOnShutdown();
|
||||
|
||||
// Check again
|
||||
ok(
|
||||
!(await checkCookie(uriA.host, {})),
|
||||
"We should not have cookies for URI: " + uriA.host
|
||||
!SiteDataTestUtils.hasCookies(originA),
|
||||
"We should not have cookies for " + originA
|
||||
);
|
||||
ok(
|
||||
!(await checkIndexedDB(uriA.host, {})),
|
||||
"We should not have IDB for URI: " + uriA.host
|
||||
!(await SiteDataTestUtils.hasIndexedDB(originA)),
|
||||
"We should not have IDB for " + originA
|
||||
);
|
||||
ok(SiteDataTestUtils.hasCookies(originB), "We have cookies for " + originB);
|
||||
ok(
|
||||
await checkCookie(uriB.host, {}),
|
||||
"We should have cookies for URI: " + uriB.host
|
||||
);
|
||||
ok(
|
||||
await checkIndexedDB(uriB.host, {}),
|
||||
"We should have IDB for URI: " + uriB.host
|
||||
await SiteDataTestUtils.hasIndexedDB(originB),
|
||||
"We have IDB for " + originB
|
||||
);
|
||||
|
||||
// Cleaning up permissions
|
||||
PermissionTestUtils.remove(uriA, "cookie");
|
||||
PermissionTestUtils.remove(uriB, "cookie");
|
||||
PermissionTestUtils.remove(originA, "cookie");
|
||||
PermissionTestUtils.remove(originB, "cookie");
|
||||
});
|
||||
|
||||
// session only cookie life-time, 2 domains (mozilla.org, www.mozilla.org),
|
||||
// only the latter has a cookie permission.
|
||||
add_task(async function subDomains() {
|
||||
// session only cookie life-time, 2 domains (sub.mozilla.org, www.mozilla.org),
|
||||
// only the former has a cookie permission.
|
||||
add_task(async function subDomains2() {
|
||||
info("Test subdomains and custom setting with cookieBehavior == 2");
|
||||
|
||||
// Let's clean up all the data.
|
||||
@ -111,68 +94,133 @@ add_task(async function subDomains() {
|
||||
});
|
||||
|
||||
// Domains and data
|
||||
let uriA = Services.io.newURI("https://sub.mozilla.org");
|
||||
PermissionTestUtils.add(uriA, "cookie", Ci.nsICookiePermission.ACCESS_ALLOW);
|
||||
|
||||
Services.cookies.add(
|
||||
uriA.host,
|
||||
"/test",
|
||||
"a",
|
||||
"b",
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
Date.now() + 24000 * 60 * 60,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET
|
||||
let originA = "https://sub.mozilla.org";
|
||||
PermissionTestUtils.add(
|
||||
originA,
|
||||
"cookie",
|
||||
Ci.nsICookiePermission.ACCESS_ALLOW
|
||||
);
|
||||
|
||||
await createIndexedDB(uriA.host, {});
|
||||
SiteDataTestUtils.addToCookies(originA);
|
||||
await SiteDataTestUtils.addToIndexedDB(originA);
|
||||
|
||||
let uriB = Services.io.newURI("https://www.mozilla.org");
|
||||
let originB = "https://www.mozilla.org";
|
||||
|
||||
Services.cookies.add(
|
||||
uriB.host,
|
||||
"/test",
|
||||
"c",
|
||||
"d",
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
Date.now() + 24000 * 60 * 60,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET
|
||||
);
|
||||
|
||||
await createIndexedDB(uriB.host, {});
|
||||
SiteDataTestUtils.addToCookies(originB);
|
||||
await SiteDataTestUtils.addToIndexedDB(originB);
|
||||
|
||||
// Check
|
||||
ok(await checkCookie(uriA.host, {}), "We have cookies for URI: " + uriA.host);
|
||||
ok(await checkIndexedDB(uriA.host, {}), "We have IDB for URI: " + uriA.host);
|
||||
ok(await checkCookie(uriB.host, {}), "We have cookies for URI: " + uriB.host);
|
||||
ok(await checkIndexedDB(uriB.host, {}), "We have IDB for URI: " + uriB.host);
|
||||
ok(SiteDataTestUtils.hasCookies(originA), "We have cookies for " + originA);
|
||||
ok(
|
||||
await SiteDataTestUtils.hasIndexedDB(originA),
|
||||
"We have IDB for " + originA
|
||||
);
|
||||
ok(SiteDataTestUtils.hasCookies(originB), "We have cookies for " + originB);
|
||||
ok(
|
||||
await SiteDataTestUtils.hasIndexedDB(originB),
|
||||
"We have IDB for " + originB
|
||||
);
|
||||
|
||||
// Cleaning up
|
||||
await Sanitizer.runSanitizeOnShutdown();
|
||||
|
||||
// Check again
|
||||
ok(SiteDataTestUtils.hasCookies(originA), "We have cookies for " + originA);
|
||||
ok(
|
||||
await checkCookie(uriA.host, {}),
|
||||
"We should have cookies for URI: " + uriA.host
|
||||
await SiteDataTestUtils.hasIndexedDB(originA),
|
||||
"We have IDB for " + originA
|
||||
);
|
||||
ok(
|
||||
await checkIndexedDB(uriA.host, {}),
|
||||
"We should have IDB for URI: " + uriA.host
|
||||
!SiteDataTestUtils.hasCookies(originB),
|
||||
"We should not have cookies for " + originB
|
||||
);
|
||||
ok(
|
||||
!(await checkCookie(uriB.host, {})),
|
||||
"We should not have cookies for URI: " + uriB.host
|
||||
);
|
||||
ok(
|
||||
!(await checkIndexedDB(uriB.host, {})),
|
||||
"We should not have IDB for URI: " + uriB.host
|
||||
!(await SiteDataTestUtils.hasIndexedDB(originB)),
|
||||
"We should not have IDB for " + originB
|
||||
);
|
||||
|
||||
// Cleaning up permissions
|
||||
PermissionTestUtils.remove(uriA, "cookie");
|
||||
PermissionTestUtils.remove(originA, "cookie");
|
||||
});
|
||||
|
||||
// session only cookie life-time, 3 domains (sub.mozilla.org, www.mozilla.org, mozilla.org),
|
||||
// only the former has a cookie permission. Both sub.mozilla.org and mozilla.org should
|
||||
// be sustained.
|
||||
add_task(async function subDomains3() {
|
||||
info(
|
||||
"Test base domain and subdomains and custom setting with cookieBehavior == 2"
|
||||
);
|
||||
|
||||
// Let's clean up all the data.
|
||||
await new Promise(resolve => {
|
||||
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, resolve);
|
||||
});
|
||||
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["network.cookie.lifetimePolicy", Ci.nsICookieService.ACCEPT_SESSION],
|
||||
["browser.sanitizer.loglevel", "All"],
|
||||
],
|
||||
});
|
||||
|
||||
// Domains and data
|
||||
let originA = "https://sub.mozilla.org";
|
||||
PermissionTestUtils.add(
|
||||
originA,
|
||||
"cookie",
|
||||
Ci.nsICookiePermission.ACCESS_ALLOW
|
||||
);
|
||||
SiteDataTestUtils.addToCookies(originA);
|
||||
await SiteDataTestUtils.addToIndexedDB(originA);
|
||||
|
||||
let originB = "https://mozilla.org";
|
||||
SiteDataTestUtils.addToCookies(originB);
|
||||
await SiteDataTestUtils.addToIndexedDB(originB);
|
||||
|
||||
let originC = "https://www.mozilla.org";
|
||||
SiteDataTestUtils.addToCookies(originC);
|
||||
await SiteDataTestUtils.addToIndexedDB(originC);
|
||||
|
||||
// Check
|
||||
ok(SiteDataTestUtils.hasCookies(originA), "We have cookies for " + originA);
|
||||
ok(
|
||||
await SiteDataTestUtils.hasIndexedDB(originA),
|
||||
"We have IDB for " + originA
|
||||
);
|
||||
ok(SiteDataTestUtils.hasCookies(originB), "We have cookies for " + originB);
|
||||
ok(
|
||||
await SiteDataTestUtils.hasIndexedDB(originB),
|
||||
"We have IDB for " + originB
|
||||
);
|
||||
ok(SiteDataTestUtils.hasCookies(originC), "We have cookies for " + originC);
|
||||
ok(
|
||||
await SiteDataTestUtils.hasIndexedDB(originC),
|
||||
"We have IDB for " + originC
|
||||
);
|
||||
|
||||
// Cleaning up
|
||||
await Sanitizer.runSanitizeOnShutdown();
|
||||
|
||||
// Check again
|
||||
ok(SiteDataTestUtils.hasCookies(originA), "We have cookies for " + originA);
|
||||
ok(
|
||||
await SiteDataTestUtils.hasIndexedDB(originA),
|
||||
"We have IDB for " + originA
|
||||
);
|
||||
ok(SiteDataTestUtils.hasCookies(originB), "We have cookies for " + originB);
|
||||
ok(
|
||||
await SiteDataTestUtils.hasIndexedDB(originB),
|
||||
"We have IDB for " + originB
|
||||
);
|
||||
ok(
|
||||
!SiteDataTestUtils.hasCookies(originC),
|
||||
"We should not have cookies for " + originC
|
||||
);
|
||||
ok(
|
||||
!(await SiteDataTestUtils.hasIndexedDB(originC)),
|
||||
"We should not have IDB for " + originC
|
||||
);
|
||||
|
||||
// Cleaning up permissions
|
||||
PermissionTestUtils.remove(originA, "cookie");
|
||||
});
|
||||
|
@ -69,7 +69,7 @@ function createDomainCookie(host, originAttributes) {
|
||||
}
|
||||
|
||||
function checkCookie(host, originAttributes) {
|
||||
for (let cookie of Services.cookies.enumerator) {
|
||||
for (let cookie of Services.cookies.cookies) {
|
||||
if (
|
||||
ChromeUtils.isOriginAttributesEqual(
|
||||
originAttributes,
|
||||
|
@ -5,6 +5,7 @@ browser.jar:
|
||||
% content browser %content/browser/ contentaccessible=yes
|
||||
|
||||
content/browser/aboutDialog-appUpdater.js (content/aboutDialog-appUpdater.js)
|
||||
content/browser/aboutDialog-appUpdater-legacy.js (content/aboutDialog-appUpdater-legacy.js)
|
||||
* content/browser/aboutDialog.xul (content/aboutDialog.xul)
|
||||
content/browser/aboutDialog.js (content/aboutDialog.js)
|
||||
content/browser/aboutDialog.css (content/aboutDialog.css)
|
||||
|
@ -65,10 +65,10 @@ add_task(async function test_cookie_getCookiesWithOriginAttributes() {
|
||||
|
||||
// Check that cookies have been set properly.
|
||||
for (let userContextId of Object.keys(USER_CONTEXTS)) {
|
||||
let enumerator = getCookiesForOA(TEST_HOST, userContextId);
|
||||
ok(enumerator.hasMoreElements(), "Cookies available");
|
||||
let cookies = getCookiesForOA(TEST_HOST, userContextId);
|
||||
ok(cookies.length, "Cookies available");
|
||||
|
||||
let foundCookie = enumerator.getNext().QueryInterface(Ci.nsICookie);
|
||||
let foundCookie = cookies[0];
|
||||
is(foundCookie.name, cookieName, "Check cookie name");
|
||||
is(foundCookie.value, USER_CONTEXTS[userContextId], "Check cookie value");
|
||||
}
|
||||
@ -89,7 +89,7 @@ add_task(async function test_cookie_getCookiesWithOriginAttributes() {
|
||||
|
||||
// Check that whether cookies has been cleared.
|
||||
for (let userContextId of Object.keys(USER_CONTEXTS)) {
|
||||
let e = getCookiesForOA(TEST_HOST, userContextId);
|
||||
ok(!e.hasMoreElements(), "No Cookie should be here");
|
||||
let cookies = getCookiesForOA(TEST_HOST, userContextId);
|
||||
ok(!cookies.length, "No Cookie should be here");
|
||||
}
|
||||
});
|
||||
|
@ -143,10 +143,10 @@ async function test_cookie_cleared() {
|
||||
}
|
||||
// Check that cookies have been set properly.
|
||||
for (let userContextId of Object.keys(USER_CONTEXTS)) {
|
||||
let enumerator = getCookiesForOA(TEST_HOST, userContextId);
|
||||
ok(enumerator.hasMoreElements(), "Cookies available");
|
||||
let cookies = getCookiesForOA(TEST_HOST, userContextId);
|
||||
ok(cookies.length, "Cookies available");
|
||||
|
||||
let foundCookie = enumerator.getNext().QueryInterface(Ci.nsICookie);
|
||||
let foundCookie = cookies[0];
|
||||
Assert.equal(foundCookie.name, COOKIE_NAME, "Check cookie name");
|
||||
Assert.equal(
|
||||
foundCookie.value,
|
||||
@ -160,8 +160,8 @@ async function test_cookie_cleared() {
|
||||
|
||||
// Check that whether cookies has been cleared or not.
|
||||
for (let userContextId of Object.keys(USER_CONTEXTS)) {
|
||||
let enumerator = getCookiesForOA(TEST_HOST, userContextId);
|
||||
ok(!enumerator.hasMoreElements(), "No Cookie should be here");
|
||||
let cookies = getCookiesForOA(TEST_HOST, userContextId);
|
||||
ok(!cookies.length, "No Cookie should be here");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,10 +52,10 @@ function checkCookies(ignoreContext = null) {
|
||||
if (ignoreContext && userContextId === String(ignoreContext)) {
|
||||
continue;
|
||||
}
|
||||
let enumerator = getCookiesForOA(TEST_HOST, userContextId);
|
||||
ok(enumerator.hasMoreElements(), "Cookies available");
|
||||
let cookies = getCookiesForOA(TEST_HOST, userContextId);
|
||||
ok(cookies.length, "Cookies available");
|
||||
|
||||
let foundCookie = enumerator.getNext().QueryInterface(Ci.nsICookie);
|
||||
let foundCookie = cookies[0];
|
||||
is(foundCookie.name, COOKIE_NAME, "Check cookie name");
|
||||
is(foundCookie.value, USER_CONTEXTS[userContextId], "Check cookie value");
|
||||
}
|
||||
@ -99,10 +99,10 @@ add_task(async function test_cookie_getCookiesWithOriginAttributes() {
|
||||
|
||||
// Check that cookies have been set properly.
|
||||
for (let userContextId of Object.keys(USER_CONTEXTS)) {
|
||||
let enumerator = getCookiesForOA(TEST_HOST, userContextId);
|
||||
ok(enumerator.hasMoreElements(), "Cookies available");
|
||||
let cookies = getCookiesForOA(TEST_HOST, userContextId);
|
||||
ok(cookies.length, "Cookies available");
|
||||
|
||||
let foundCookie = enumerator.getNext().QueryInterface(Ci.nsICookie);
|
||||
let foundCookie = cookies[0];
|
||||
is(foundCookie.name, COOKIE_NAME, "Check cookie name");
|
||||
is(foundCookie.value, USER_CONTEXTS[userContextId], "Check cookie value");
|
||||
}
|
||||
@ -116,7 +116,7 @@ add_task(async function test_cookie_getCookiesWithOriginAttributes() {
|
||||
|
||||
// Check that whether cookies has been cleared.
|
||||
for (let userContextId of Object.keys(USER_CONTEXTS)) {
|
||||
let e = getCookiesForOA(TEST_HOST, userContextId);
|
||||
ok(!e.hasMoreElements(), "No Cookie should be here");
|
||||
let cookies = getCookiesForOA(TEST_HOST, userContextId);
|
||||
ok(!cookies.length, "No Cookie should be here");
|
||||
}
|
||||
});
|
||||
|
@ -270,9 +270,13 @@ var Policies = {
|
||||
return;
|
||||
}
|
||||
let certFile = reader.result;
|
||||
let certFileArray = [];
|
||||
for (let i = 0; i < certFile.length; i++) {
|
||||
certFileArray.push(certFile.charCodeAt(i));
|
||||
}
|
||||
let cert;
|
||||
try {
|
||||
cert = gCertDB.constructX509(certFile);
|
||||
cert = gCertDB.constructX509(certFileArray);
|
||||
} catch (e) {
|
||||
try {
|
||||
// It might be PEM instead of DER.
|
||||
|
@ -64,8 +64,8 @@ async function test_cookie_settings({
|
||||
Ci.nsIHttpChannelInternal
|
||||
).forceAllowThirdPartyCookie = true;
|
||||
Services.cookies.removeAll();
|
||||
Services.cookies.setCookieString(firstPartyURI, null, "key=value", channel);
|
||||
Services.cookies.setCookieString(thirdPartyURI, null, "key=value", channel);
|
||||
Services.cookies.setCookieString(firstPartyURI, "key=value", channel);
|
||||
Services.cookies.setCookieString(thirdPartyURI, "key=value", channel);
|
||||
|
||||
let expectedFirstPartyCookies = 1;
|
||||
let expectedThirdPartyCookies = 1;
|
||||
@ -91,7 +91,6 @@ async function test_cookie_settings({
|
||||
Services.cookies.removeAll();
|
||||
Services.cookies.setCookieString(
|
||||
firstPartyURI,
|
||||
null,
|
||||
"key=value; max-age=1000",
|
||||
channel
|
||||
);
|
||||
|
@ -61,7 +61,7 @@ const clearCookies = async function(options) {
|
||||
|
||||
if (options.since || options.hostnames) {
|
||||
// Iterate through the cookies and delete any created after our cutoff.
|
||||
for (const cookie of cookieMgr.enumerator) {
|
||||
for (const cookie of cookieMgr.cookies) {
|
||||
if (
|
||||
(!options.since ||
|
||||
cookie.creationTime >= PlacesUtils.toPRTime(options.since)) &&
|
||||
|
@ -0,0 +1,54 @@
|
||||
"use strict";
|
||||
|
||||
loadTestSubscript("head_devtools.js");
|
||||
|
||||
const FILE_URL = Services.io.newFileURI(
|
||||
new FileUtils.File(getTestFilePath("file_dummy.html"))
|
||||
).spec;
|
||||
|
||||
add_task(async function test_devtools_inspectedWindow_eval_in_file_url() {
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, FILE_URL);
|
||||
|
||||
async function devtools_page() {
|
||||
try {
|
||||
const [
|
||||
evalResult,
|
||||
errorResult,
|
||||
] = await browser.devtools.inspectedWindow.eval("location.protocol");
|
||||
browser.test.assertEq(undefined, errorResult, "eval should not fail");
|
||||
browser.test.assertEq("file:", evalResult, "eval should succeed");
|
||||
browser.test.notifyPass("inspectedWindow-eval-file");
|
||||
} catch (err) {
|
||||
browser.test.fail(`Error: ${err} :: ${err.stack}`);
|
||||
browser.test.notifyFail("inspectedWindow-eval-file");
|
||||
}
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
devtools_page: "devtools_page.html",
|
||||
},
|
||||
files: {
|
||||
"devtools_page.html": `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script src="devtools_page.js"></script>
|
||||
</head>
|
||||
</html>`,
|
||||
"devtools_page.js": devtools_page,
|
||||
},
|
||||
});
|
||||
|
||||
await extension.startup();
|
||||
|
||||
await openToolboxForTab(tab);
|
||||
|
||||
await extension.awaitFinish("inspectedWindow-eval-file");
|
||||
|
||||
await closeToolboxForTab(tab);
|
||||
|
||||
await extension.unload();
|
||||
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
});
|
@ -1,5 +1,9 @@
|
||||
"use strict";
|
||||
|
||||
const FILE_URL = Services.io.newFileURI(
|
||||
new FileUtils.File(getTestFilePath("file_dummy.html"))
|
||||
).spec;
|
||||
|
||||
async function testTabsCreateInvalidURL(tabsCreateURL) {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
@ -62,6 +66,7 @@ add_task(async function() {
|
||||
tabsCreateURL: "javascript:console.log('tabs.update execute javascript')",
|
||||
},
|
||||
{ tabsCreateURL: dataURLPage },
|
||||
{ tabsCreateURL: FILE_URL },
|
||||
];
|
||||
|
||||
for (let { tabsCreateURL } of testCases) {
|
||||
|
@ -0,0 +1,91 @@
|
||||
"use strict";
|
||||
|
||||
const FILE_URL = Services.io.newFileURI(
|
||||
new FileUtils.File(getTestFilePath("file_dummy.html"))
|
||||
).spec;
|
||||
|
||||
add_task(async function testExecuteScript_at_file_url() {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
permissions: ["tabs", "file:///*"],
|
||||
},
|
||||
background() {
|
||||
browser.test.onMessage.addListener(async () => {
|
||||
try {
|
||||
const [tab] = await browser.tabs.query({ url: "file://*/*/*dummy*" });
|
||||
const result = await browser.tabs.executeScript(tab.id, {
|
||||
code: "location.protocol",
|
||||
});
|
||||
browser.test.assertEq(
|
||||
"file:",
|
||||
result[0],
|
||||
"Script executed correctly in new tab"
|
||||
);
|
||||
browser.test.notifyPass("executeScript");
|
||||
} catch (e) {
|
||||
browser.test.fail(`Error: ${e} :: ${e.stack}`);
|
||||
browser.test.notifyFail("executeScript");
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
await extension.startup();
|
||||
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, FILE_URL);
|
||||
|
||||
extension.sendMessage();
|
||||
await extension.awaitFinish("executeScript");
|
||||
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
|
||||
await extension.unload();
|
||||
});
|
||||
|
||||
add_task(async function testExecuteScript_at_file_url_with_activeTab() {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
permissions: ["activeTab"],
|
||||
browser_action: {},
|
||||
},
|
||||
background() {
|
||||
browser.browserAction.onClicked.addListener(async tab => {
|
||||
try {
|
||||
const result = await browser.tabs.executeScript(tab.id, {
|
||||
code: "location.protocol",
|
||||
});
|
||||
browser.test.assertEq(
|
||||
"file:",
|
||||
result[0],
|
||||
"Script executed correctly in active tab"
|
||||
);
|
||||
browser.test.notifyPass("executeScript");
|
||||
} catch (e) {
|
||||
browser.test.fail(`Error: ${e} :: ${e.stack}`);
|
||||
browser.test.notifyFail("executeScript");
|
||||
}
|
||||
});
|
||||
|
||||
browser.test.onMessage.addListener(async () => {
|
||||
await browser.test.assertRejects(
|
||||
browser.tabs.executeScript({ code: "location.protocol" }),
|
||||
/Missing host permission for the tab/,
|
||||
"activeTab not active yet, executeScript should be rejected"
|
||||
);
|
||||
browser.test.sendMessage("next-step");
|
||||
});
|
||||
},
|
||||
});
|
||||
await extension.startup();
|
||||
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, FILE_URL);
|
||||
|
||||
extension.sendMessage();
|
||||
await extension.awaitMessage("next-step");
|
||||
|
||||
await clickBrowserAction(extension);
|
||||
await extension.awaitFinish("executeScript");
|
||||
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
|
||||
await extension.unload();
|
||||
});
|
@ -317,11 +317,9 @@ class TestFirefoxRefresh(MarionetteTestCase):
|
||||
def checkCookie(self):
|
||||
cookieInfo = self.runCode("""
|
||||
try {
|
||||
let cookieEnum = Services.cookies.getCookiesFromHost(arguments[0], {});
|
||||
let cookies = Services.cookies.getCookiesFromHost(arguments[0], {});
|
||||
let cookie = null;
|
||||
while (cookieEnum.hasMoreElements()) {
|
||||
let hostCookie = cookieEnum.getNext();
|
||||
hostCookie.QueryInterface(Ci.nsICookie);
|
||||
for (let hostCookie of cookies) {
|
||||
// getCookiesFromHost returns any cookie from the BASE host.
|
||||
if (hostCookie.rawHost != arguments[0])
|
||||
continue;
|
||||
|
@ -54,9 +54,9 @@ add_task(async function() {
|
||||
);
|
||||
|
||||
// Now check the cookie details.
|
||||
let enumerator = Services.cookies.getCookiesFromHost(COOKIE.host, {});
|
||||
Assert.ok(enumerator.hasMoreElements(), "Cookies available");
|
||||
let foundCookie = enumerator.getNext().QueryInterface(Ci.nsICookie);
|
||||
let cookies = Services.cookies.getCookiesFromHost(COOKIE.host, {});
|
||||
Assert.ok(cookies.length, "Cookies available");
|
||||
let foundCookie = cookies[0];
|
||||
|
||||
for (let prop of Object.keys(COOKIE)) {
|
||||
Assert.equal(foundCookie[prop], COOKIE[prop], "Check cookie " + prop);
|
||||
|
@ -138,9 +138,9 @@ add_task(async function() {
|
||||
);
|
||||
|
||||
// Now check the cookie details.
|
||||
let enumerator = Services.cookies.getCookiesFromHost(COOKIE.host, {});
|
||||
Assert.ok(enumerator.hasMoreElements());
|
||||
let foundCookie = enumerator.getNext().QueryInterface(Ci.nsICookie);
|
||||
let cookies = Services.cookies.getCookiesFromHost(COOKIE.host, {});
|
||||
Assert.ok(cookies.length);
|
||||
let foundCookie = cookies[0];
|
||||
|
||||
Assert.equal(foundCookie.name, COOKIE.name);
|
||||
Assert.equal(foundCookie.value, COOKIE.value);
|
||||
|
@ -218,6 +218,7 @@ async function doTest(aBrowser) {
|
||||
audioSource.setAttribute("type", "audio/ogg");
|
||||
audioTrack.setAttribute("src", trackURL);
|
||||
audioTrack.setAttribute("kind", "subtitles");
|
||||
audioTrack.setAttribute("default", true);
|
||||
|
||||
audio.appendChild(audioSource);
|
||||
audio.appendChild(audioTrack);
|
||||
|
@ -76,7 +76,7 @@ add_task(async function cookie_test() {
|
||||
await BrowserTestUtils.browserLoaded(tab.linkedBrowser, true);
|
||||
|
||||
let count = 0;
|
||||
for (let cookie of Services.cookies.enumerator) {
|
||||
for (let cookie of Services.cookies.cookies) {
|
||||
count++;
|
||||
Assert.equal(cookie.value, "foo", "Cookie value should be foo");
|
||||
Assert.equal(
|
||||
|
@ -261,12 +261,11 @@ add_task(async function() {
|
||||
|
||||
// Get the exact creation date from the cookies (to avoid intermittents
|
||||
// from minimal time differences, since we round up to minutes).
|
||||
let cookiesEnum1 = Services.cookies.getCookiesFromHost(uri.host, {});
|
||||
let cookies1 = Services.cookies.getCookiesFromHost(uri.host, {});
|
||||
let cookies2 = Services.cookies.getCookiesFromHost(uri2.host, {});
|
||||
// We made two valid cookies for example.com.
|
||||
cookiesEnum1.getNext();
|
||||
let cookiesEnum2 = Services.cookies.getCookiesFromHost(uri2.host, {});
|
||||
let cookie1 = cookiesEnum1.getNext().QueryInterface(Ci.nsICookie);
|
||||
let cookie2 = cookiesEnum2.getNext().QueryInterface(Ci.nsICookie);
|
||||
let cookie1 = cookies1[1];
|
||||
let cookie2 = cookies2[0];
|
||||
|
||||
let fullFormatter = new Services.intl.DateTimeFormat(undefined, {
|
||||
dateStyle: "short",
|
||||
|
@ -13,24 +13,20 @@ let gSiteDataRemoveSelected = {
|
||||
for (let host of hosts) {
|
||||
let listItem = document.createXULElement("richlistitem");
|
||||
let label = document.createXULElement("label");
|
||||
label.setAttribute("value", host);
|
||||
if (host) {
|
||||
label.setAttribute("value", host);
|
||||
} else {
|
||||
document.l10n.setAttributes(label, "site-data-local-file-host");
|
||||
}
|
||||
listItem.appendChild(label);
|
||||
fragment.appendChild(listItem);
|
||||
}
|
||||
list.appendChild(fragment);
|
||||
document.addEventListener("dialogaccept", function() {
|
||||
gSiteDataRemoveSelected.ondialogaccept();
|
||||
window.arguments[0].allowed = true;
|
||||
});
|
||||
document.addEventListener("dialogcancel", function() {
|
||||
gSiteDataRemoveSelected.ondialogcancel();
|
||||
window.arguments[0].allowed = false;
|
||||
});
|
||||
},
|
||||
|
||||
ondialogaccept() {
|
||||
window.arguments[0].allowed = true;
|
||||
},
|
||||
|
||||
ondialogcancel() {
|
||||
window.arguments[0].allowed = false;
|
||||
},
|
||||
};
|
||||
|
@ -60,7 +60,10 @@ let gSiteDataSettings = {
|
||||
}
|
||||
|
||||
// Add "Host" column.
|
||||
addColumnItem({ raw: site.host }, "4");
|
||||
let hostData = site.host
|
||||
? { raw: site.host }
|
||||
: { id: "site-data-local-file-host" };
|
||||
addColumnItem(hostData, "4");
|
||||
|
||||
// Add "Cookies" column.
|
||||
addColumnItem({ raw: site.cookies.length }, "1");
|
||||
|
@ -194,7 +194,7 @@ var SessionCookiesInternal = {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let cookie of Services.cookies.sessionEnumerator) {
|
||||
for (let cookie of Services.cookies.sessionCookies) {
|
||||
this._addCookie(cookie);
|
||||
}
|
||||
},
|
||||
|
@ -25,7 +25,7 @@ add_task(async function() {
|
||||
|
||||
// verify our cookie got set during pageload
|
||||
let i = 0;
|
||||
for (var cookie of Services.cookies.enumerator) {
|
||||
for (var cookie of Services.cookies.cookies) {
|
||||
i++;
|
||||
}
|
||||
Assert.equal(i, 1, "expected one cookie");
|
||||
@ -37,7 +37,7 @@ add_task(async function() {
|
||||
await setBrowserState(state);
|
||||
|
||||
// at this point, the cookie should be restored...
|
||||
for (var cookie2 of Services.cookies.enumerator) {
|
||||
for (var cookie2 of Services.cookies.cookies) {
|
||||
if (cookie.name == cookie2.name) {
|
||||
break;
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "imgIContainer.h"
|
||||
#include "imgIRequest.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIImageLoadingContent.h"
|
||||
#include "nsIOutputStream.h"
|
||||
|
@ -26,13 +26,13 @@ let chooseCertificateCalled = false;
|
||||
|
||||
const clientAuthDialogs = {
|
||||
chooseCertificate(
|
||||
ctx,
|
||||
hostname,
|
||||
port,
|
||||
organization,
|
||||
issuerOrg,
|
||||
certList,
|
||||
selectedIndex
|
||||
selectedIndex,
|
||||
rememberClientAuthCertificate
|
||||
) {
|
||||
ok(
|
||||
expectingChooseCertificate,
|
||||
@ -42,6 +42,7 @@ const clientAuthDialogs = {
|
||||
);
|
||||
is(certList.length, 1, "should have only one client certificate available");
|
||||
selectedIndex.value = 0;
|
||||
rememberClientAuthCertificate.value = false;
|
||||
chooseCertificateCalled = true;
|
||||
return true;
|
||||
},
|
||||
|
@ -1 +1 @@
|
||||
68.14.1
|
||||
68.14.2
|
||||
|
@ -1 +1 @@
|
||||
68.14.1b
|
||||
68.14.2b
|
||||
|
Binary file not shown.
@ -23,6 +23,9 @@ site-data-column-storage =
|
||||
site-data-column-last-used =
|
||||
.label = Last Used
|
||||
|
||||
# This label is used in the "Host" column for local files, which have no host.
|
||||
site-data-local-file-host = (local file)
|
||||
|
||||
site-data-remove-selected =
|
||||
.label = Remove Selected
|
||||
.accesskey = R
|
||||
|
@ -430,10 +430,6 @@ offlineApps.allowStoring.accesskey=A
|
||||
offlineApps.dontAllow.label=Don’t Allow
|
||||
offlineApps.dontAllow.accesskey=n
|
||||
|
||||
offlineApps.usage=This website (%S) is now storing more than %SMB of data on your computer for offline use.
|
||||
offlineApps.manageUsage=Show settings
|
||||
offlineApps.manageUsageAccessKey=S
|
||||
|
||||
# Canvas permission prompt
|
||||
# LOCALIZATION NOTE (canvas.siteprompt): %S is hostname
|
||||
canvas.siteprompt=Will you allow %S to use your HTML5 canvas image data? This may be used to uniquely identify your computer.
|
||||
|
508
browser/modules/AppUpdater.jsm
Normal file
508
browser/modules/AppUpdater.jsm
Normal file
@ -0,0 +1,508 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["AppUpdater"];
|
||||
|
||||
var { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
AppConstants: "resource://gre/modules/AppConstants.jsm",
|
||||
Services: "resource://gre/modules/Services.jsm",
|
||||
UpdateUtils: "resource://gre/modules/UpdateUtils.jsm",
|
||||
});
|
||||
|
||||
const PREF_APP_UPDATE_CANCELATIONS_OSX = "app.update.cancelations.osx";
|
||||
const PREF_APP_UPDATE_ELEVATE_NEVER = "app.update.elevate.never";
|
||||
|
||||
/**
|
||||
* This class checks for app updates in the foreground. It has several public
|
||||
* methods for checking for updates, downloading updates, stopping the current
|
||||
* update, and getting the current update status. It can also register
|
||||
* listeners that will be called back as different stages of updates occur.
|
||||
*/
|
||||
class AppUpdater {
|
||||
constructor() {
|
||||
this._listeners = new Set();
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
"aus",
|
||||
"@mozilla.org/updates/update-service;1",
|
||||
"nsIApplicationUpdateService"
|
||||
);
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
"checker",
|
||||
"@mozilla.org/updates/update-checker;1",
|
||||
"nsIUpdateChecker"
|
||||
);
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
"um",
|
||||
"@mozilla.org/updates/update-manager;1",
|
||||
"nsIUpdateManager"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The main entry point for checking for updates. As different stages of the
|
||||
* check and possible subsequent update occur, the updater's status is set and
|
||||
* listeners are called.
|
||||
*/
|
||||
check() {
|
||||
if (!AppConstants.MOZ_UPDATER) {
|
||||
this._setStatus(AppUpdater.STATUS.NO_UPDATER);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.updateDisabledByPolicy) {
|
||||
this._setStatus(AppUpdater.STATUS.UPDATE_DISABLED_BY_POLICY);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isReadyForRestart) {
|
||||
this._setStatus(AppUpdater.STATUS.READY_FOR_RESTART);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.aus.isOtherInstanceHandlingUpdates) {
|
||||
this._setStatus(AppUpdater.STATUS.OTHER_INSTANCE_HANDLING_UPDATES);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isDownloading) {
|
||||
this.startDownload();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isStaging) {
|
||||
this._waitForUpdateToStage();
|
||||
return;
|
||||
}
|
||||
|
||||
// We might need this value later, so start loading it from the disk now.
|
||||
this.promiseAutoUpdateSetting = UpdateUtils.getAppUpdateAutoEnabled();
|
||||
|
||||
// That leaves the options
|
||||
// "Check for updates, but let me choose whether to install them", and
|
||||
// "Automatically install updates".
|
||||
// In both cases, we check for updates without asking.
|
||||
// In the "let me choose" case, we ask before downloading though, in onCheckComplete.
|
||||
this.checkForUpdates();
|
||||
}
|
||||
|
||||
// true when there is an update ready to be applied on restart or staged.
|
||||
get isPending() {
|
||||
if (this.update) {
|
||||
return (
|
||||
this.update.state == "pending" ||
|
||||
this.update.state == "pending-service" ||
|
||||
this.update.state == "pending-elevate"
|
||||
);
|
||||
}
|
||||
return (
|
||||
this.um.activeUpdate &&
|
||||
(this.um.activeUpdate.state == "pending" ||
|
||||
this.um.activeUpdate.state == "pending-service" ||
|
||||
this.um.activeUpdate.state == "pending-elevate")
|
||||
);
|
||||
}
|
||||
|
||||
// true when there is an update already staged.
|
||||
get isApplied() {
|
||||
if (this.update) {
|
||||
return (
|
||||
this.update.state == "applied" || this.update.state == "applied-service"
|
||||
);
|
||||
}
|
||||
return (
|
||||
this.um.activeUpdate &&
|
||||
(this.um.activeUpdate.state == "applied" ||
|
||||
this.um.activeUpdate.state == "applied-service")
|
||||
);
|
||||
}
|
||||
|
||||
get isStaging() {
|
||||
if (!this.updateStagingEnabled) {
|
||||
return false;
|
||||
}
|
||||
let errorCode;
|
||||
if (this.update) {
|
||||
errorCode = this.update.errorCode;
|
||||
} else if (this.um.activeUpdate) {
|
||||
errorCode = this.um.activeUpdate.errorCode;
|
||||
}
|
||||
// If the state is pending and the error code is not 0, staging must have
|
||||
// failed.
|
||||
return this.isPending && errorCode == 0;
|
||||
}
|
||||
|
||||
// true when an update ready to restart to finish the update process.
|
||||
get isReadyForRestart() {
|
||||
if (this.updateStagingEnabled) {
|
||||
let errorCode;
|
||||
if (this.update) {
|
||||
errorCode = this.update.errorCode;
|
||||
} else if (this.um.activeUpdate) {
|
||||
errorCode = this.um.activeUpdate.errorCode;
|
||||
}
|
||||
// If the state is pending and the error code is not 0, staging must have
|
||||
// failed and Firefox should be restarted to try to apply the update
|
||||
// without staging.
|
||||
return this.isApplied || (this.isPending && errorCode != 0);
|
||||
}
|
||||
return this.isPending;
|
||||
}
|
||||
|
||||
// true when there is an update download in progress.
|
||||
get isDownloading() {
|
||||
if (this.update) {
|
||||
return this.update.state == "downloading";
|
||||
}
|
||||
return this.um.activeUpdate && this.um.activeUpdate.state == "downloading";
|
||||
}
|
||||
|
||||
// true when updating has been disabled by enterprise policy
|
||||
get updateDisabledByPolicy() {
|
||||
return Services.policies && !Services.policies.isAllowed("appUpdate");
|
||||
}
|
||||
|
||||
// true when updating in background is enabled.
|
||||
get updateStagingEnabled() {
|
||||
return !this.updateDisabledByPolicy && this.aus.canStageUpdates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for updates
|
||||
*/
|
||||
checkForUpdates() {
|
||||
// Clear prefs that could prevent a user from discovering available updates.
|
||||
if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_CANCELATIONS_OSX)) {
|
||||
Services.prefs.clearUserPref(PREF_APP_UPDATE_CANCELATIONS_OSX);
|
||||
}
|
||||
if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_ELEVATE_NEVER)) {
|
||||
Services.prefs.clearUserPref(PREF_APP_UPDATE_ELEVATE_NEVER);
|
||||
}
|
||||
this._setStatus(AppUpdater.STATUS.CHECKING);
|
||||
this.checker.checkForUpdates(this._updateCheckListener, true);
|
||||
// after checking, onCheckComplete() is called
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements nsIUpdateCheckListener. The methods implemented by
|
||||
* nsIUpdateCheckListener are in a different scope from nsIIncrementalDownload
|
||||
* to make it clear which are used by each interface.
|
||||
*/
|
||||
get _updateCheckListener() {
|
||||
if (!this.__updateCheckListener) {
|
||||
this.__updateCheckListener = {
|
||||
/**
|
||||
* See nsIUpdateService.idl
|
||||
*/
|
||||
onCheckComplete: (aRequest, aUpdates) => {
|
||||
this.update = this.aus.selectUpdate(aUpdates);
|
||||
if (!this.update) {
|
||||
this._setStatus(AppUpdater.STATUS.NO_UPDATES_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.update.unsupported) {
|
||||
this._setStatus(AppUpdater.STATUS.UNSUPPORTED_SYSTEM);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.aus.canApplyUpdates) {
|
||||
this._setStatus(AppUpdater.STATUS.MANUAL_UPDATE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.promiseAutoUpdateSetting) {
|
||||
this.promiseAutoUpdateSetting = UpdateUtils.getAppUpdateAutoEnabled();
|
||||
}
|
||||
this.promiseAutoUpdateSetting.then(updateAuto => {
|
||||
if (updateAuto) {
|
||||
// automatically download and install
|
||||
this.startDownload();
|
||||
} else {
|
||||
// ask
|
||||
this._setStatus(AppUpdater.STATUS.DOWNLOAD_AND_INSTALL);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsIUpdateService.idl
|
||||
*/
|
||||
onError: (aRequest, aUpdate) => {
|
||||
// Errors in the update check are treated as no updates found. If the
|
||||
// update check fails repeatedly without a success the user will be
|
||||
// notified with the normal app update user interface so this is safe.
|
||||
this._setStatus(AppUpdater.STATUS.NO_UPDATES_FOUND);
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsISupports.idl
|
||||
*/
|
||||
QueryInterface: ChromeUtils.generateQI(["nsIUpdateCheckListener"]),
|
||||
};
|
||||
}
|
||||
return this.__updateCheckListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the status to STAGING. The status will then be set again when the
|
||||
* update finishes staging.
|
||||
*/
|
||||
_waitForUpdateToStage() {
|
||||
if (!this.update) {
|
||||
this.update = this.um.activeUpdate;
|
||||
}
|
||||
this.update.QueryInterface(Ci.nsIWritablePropertyBag);
|
||||
this.update.setProperty("foregroundDownload", "true");
|
||||
this._setStatus(AppUpdater.STATUS.STAGING);
|
||||
this._awaitStagingComplete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the download of an update mar.
|
||||
*/
|
||||
startDownload() {
|
||||
if (!this.update) {
|
||||
this.update = this.um.activeUpdate;
|
||||
}
|
||||
this.update.QueryInterface(Ci.nsIWritablePropertyBag);
|
||||
this.update.setProperty("foregroundDownload", "true");
|
||||
|
||||
let state = this.aus.downloadUpdate(this.update, false);
|
||||
if (state == "failed") {
|
||||
this._setStatus(AppUpdater.STATUS.DOWNLOAD_FAILED);
|
||||
return;
|
||||
}
|
||||
|
||||
this._setupDownloadListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts tracking the download.
|
||||
*/
|
||||
_setupDownloadListener() {
|
||||
this._setStatus(AppUpdater.STATUS.DOWNLOADING);
|
||||
this.aus.addDownloadListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* See nsIRequestObserver.idl
|
||||
*/
|
||||
onStartRequest(aRequest) {}
|
||||
|
||||
/**
|
||||
* See nsIRequestObserver.idl
|
||||
*/
|
||||
onStopRequest(aRequest, aStatusCode) {
|
||||
switch (aStatusCode) {
|
||||
case Cr.NS_ERROR_UNEXPECTED:
|
||||
if (
|
||||
this.update.selectedPatch.state == "download-failed" &&
|
||||
(this.update.isCompleteUpdate || this.update.patchCount != 2)
|
||||
) {
|
||||
// Verification error of complete patch, informational text is held in
|
||||
// the update object.
|
||||
this.aus.removeDownloadListener(this);
|
||||
this._setStatus(AppUpdater.STATUS.DOWNLOAD_FAILED);
|
||||
break;
|
||||
}
|
||||
// Verification failed for a partial patch, complete patch is now
|
||||
// downloading so return early and do NOT remove the download listener!
|
||||
break;
|
||||
case Cr.NS_BINDING_ABORTED:
|
||||
// Do not remove UI listener since the user may resume downloading again.
|
||||
break;
|
||||
case Cr.NS_OK:
|
||||
this.aus.removeDownloadListener(this);
|
||||
if (this.updateStagingEnabled) {
|
||||
this._setStatus(AppUpdater.STATUS.STAGING);
|
||||
this._awaitStagingComplete();
|
||||
} else {
|
||||
this._setStatus(AppUpdater.STATUS.READY_FOR_RESTART);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
this.aus.removeDownloadListener(this);
|
||||
this._setStatus(AppUpdater.STATUS.DOWNLOAD_FAILED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See nsIProgressEventSink.idl
|
||||
*/
|
||||
onStatus(aRequest, aStatus, aStatusArg) {}
|
||||
|
||||
/**
|
||||
* See nsIProgressEventSink.idl
|
||||
*/
|
||||
onProgress(aRequest, aProgress, aProgressMax) {
|
||||
this._setStatus(AppUpdater.STATUS.DOWNLOADING, aProgress, aProgressMax);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function registers an observer that watches for the staging process
|
||||
* to complete. Once it does, it sets the status to either request that the
|
||||
* user restarts to install the update on success, request that the user
|
||||
* manually download and install the newer version, or automatically download
|
||||
* a complete update if applicable.
|
||||
*/
|
||||
_awaitStagingComplete() {
|
||||
let observer = (aSubject, aTopic, aData) => {
|
||||
// Update the UI when the background updater is finished
|
||||
let status = aData;
|
||||
if (
|
||||
status == "applied" ||
|
||||
status == "applied-service" ||
|
||||
status == "pending" ||
|
||||
status == "pending-service" ||
|
||||
status == "pending-elevate"
|
||||
) {
|
||||
// If the update is successfully applied, or if the updater has
|
||||
// fallen back to non-staged updates, show the "Restart to Update"
|
||||
// button.
|
||||
this._setStatus(AppUpdater.STATUS.READY_FOR_RESTART);
|
||||
} else if (status == "failed") {
|
||||
// Background update has failed, let's show the UI responsible for
|
||||
// prompting the user to update manually.
|
||||
this._setStatus(AppUpdater.STATUS.DOWNLOAD_FAILED);
|
||||
} else if (status == "downloading") {
|
||||
// We've fallen back to downloading the complete update because the
|
||||
// partial update failed to get staged in the background.
|
||||
// Therefore we need to keep our observer.
|
||||
this._setupDownloadListener();
|
||||
return;
|
||||
}
|
||||
Services.obs.removeObserver(observer, "update-staged");
|
||||
};
|
||||
Services.obs.addObserver(observer, "update-staged");
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the current check for updates and any ongoing download.
|
||||
*/
|
||||
stop() {
|
||||
this.checker.stopCurrentCheck();
|
||||
this.aus.removeDownloadListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* {AppUpdater.STATUS} The status of the current check or update.
|
||||
*/
|
||||
get status() {
|
||||
if (!this._status) {
|
||||
if (!AppConstants.MOZ_UPDATER) {
|
||||
this._status = AppUpdater.STATUS.NO_UPDATER;
|
||||
} else if (this.updateDisabledByPolicy) {
|
||||
this._status = AppUpdater.STATUS.UPDATE_DISABLED_BY_POLICY;
|
||||
} else if (this.isReadyForRestart) {
|
||||
this._status = AppUpdater.STATUS.READY_FOR_RESTART;
|
||||
} else if (this.aus.isOtherInstanceHandlingUpdates) {
|
||||
this._status = AppUpdater.STATUS.OTHER_INSTANCE_HANDLING_UPDATES;
|
||||
} else if (this.isDownloading) {
|
||||
this._status = AppUpdater.STATUS.DOWNLOADING;
|
||||
} else if (this.isStaging) {
|
||||
this._status = AppUpdater.STATUS.STAGING;
|
||||
} else {
|
||||
this._status = AppUpdater.STATUS.NEVER_CHECKED;
|
||||
}
|
||||
}
|
||||
return this._status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener function that will be called back on status changes as
|
||||
* different stages of updates occur. The function will be called without
|
||||
* arguments for most status changes; see the comments around the STATUS value
|
||||
* definitions below. This is safe to call multiple times with the same
|
||||
* function. It will be added only once.
|
||||
*
|
||||
* @param {function} listener
|
||||
* The listener function to add.
|
||||
*/
|
||||
addListener(listener) {
|
||||
this._listeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a listener. This is safe to call multiple times with the same
|
||||
* function, or with a function that was never added.
|
||||
*
|
||||
* @param {function} listener
|
||||
* The listener function to remove.
|
||||
*/
|
||||
removeListener(listener) {
|
||||
this._listeners.delete(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the updater's current status and calls listeners.
|
||||
*
|
||||
* @param {AppUpdater.STATUS} status
|
||||
* The new updater status.
|
||||
* @param {*} listenerArgs
|
||||
* Arguments to pass to listeners.
|
||||
*/
|
||||
_setStatus(status, ...listenerArgs) {
|
||||
this._status = status;
|
||||
for (let listener of this._listeners) {
|
||||
listener(status, ...listenerArgs);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
AppUpdater.STATUS = {
|
||||
// Updates are allowed and there's no downloaded or staged update, but the
|
||||
// AppUpdater hasn't checked for updates yet, so it doesn't know more than
|
||||
// that.
|
||||
NEVER_CHECKED: 0,
|
||||
|
||||
// The updater isn't available (AppConstants.MOZ_UPDATER is falsey).
|
||||
NO_UPDATER: 1,
|
||||
|
||||
// "appUpdate" is not allowed by policy.
|
||||
UPDATE_DISABLED_BY_POLICY: 2,
|
||||
|
||||
// Another app instance is handling updates.
|
||||
OTHER_INSTANCE_HANDLING_UPDATES: 3,
|
||||
|
||||
// There's an update, but it's not supported on this system.
|
||||
UNSUPPORTED_SYSTEM: 4,
|
||||
|
||||
// The user must apply updates manually.
|
||||
MANUAL_UPDATE: 5,
|
||||
|
||||
// The AppUpdater is checking for updates.
|
||||
CHECKING: 6,
|
||||
|
||||
// The AppUpdater checked for updates and none were found.
|
||||
NO_UPDATES_FOUND: 7,
|
||||
|
||||
// The AppUpdater is downloading an update. Listeners are notified of this
|
||||
// status as a download starts. They are also notified on download progress,
|
||||
// and in that case they are passed two arguments: the current download
|
||||
// progress and the total download size.
|
||||
DOWNLOADING: 8,
|
||||
|
||||
// The AppUpdater tried to download an update but it failed.
|
||||
DOWNLOAD_FAILED: 9,
|
||||
|
||||
// There's an update available, but the user wants us to ask them to download
|
||||
// and install it.
|
||||
DOWNLOAD_AND_INSTALL: 10,
|
||||
|
||||
// An update is staging.
|
||||
STAGING: 11,
|
||||
|
||||
// An update is downloaded and staged and will be applied on restart.
|
||||
READY_FOR_RESTART: 12,
|
||||
};
|
@ -128,15 +128,6 @@ class FaviconLoad {
|
||||
iconInfo.node.ownerGlobal.document.documentLoadGroup;
|
||||
this.channel.notificationCallbacks = this;
|
||||
|
||||
if (this.channel instanceof Ci.nsIHttpChannel) {
|
||||
try {
|
||||
let acceptHeader = Services.prefs.getCharPref("image.http.accept");
|
||||
this.channel.setRequestHeader("Accept", acceptHeader, false);
|
||||
} catch (e) {
|
||||
// Failing to get the pref or set the header is ignorable.
|
||||
}
|
||||
}
|
||||
|
||||
if (this.channel instanceof Ci.nsIHttpChannelInternal) {
|
||||
this.channel.blockAuthPrompt = true;
|
||||
}
|
||||
|
@ -497,7 +497,8 @@ var Sanitizer = {
|
||||
Ci.nsIClearDataService.CLEAR_PERMISSIONS |
|
||||
Ci.nsIClearDataService.CLEAR_CONTENT_PREFERENCES |
|
||||
Ci.nsIClearDataService.CLEAR_DOM_PUSH_NOTIFICATIONS |
|
||||
Ci.nsIClearDataService.CLEAR_SECURITY_SETTINGS
|
||||
Ci.nsIClearDataService.CLEAR_SECURITY_SETTINGS |
|
||||
Ci.nsIClearDataService.CLEAR_CERT_EXCEPTIONS
|
||||
);
|
||||
TelemetryStopwatch.finish("FX_SANITIZE_SITESETTINGS", refObj);
|
||||
},
|
||||
@ -807,9 +808,9 @@ class PrincipalsCollector {
|
||||
|
||||
// Let's take the list of unique hosts+OA from cookies.
|
||||
progress.step = "principals-cookies";
|
||||
let enumerator = Services.cookies.enumerator;
|
||||
let cookies = Services.cookies.cookies;
|
||||
let hosts = new Set();
|
||||
for (let cookie of enumerator) {
|
||||
for (let cookie of cookies) {
|
||||
hosts.add(
|
||||
cookie.rawHost +
|
||||
ChromeUtils.originAttributesToSuffix(cookie.originAttributes)
|
||||
|
@ -176,7 +176,7 @@ var SiteDataManager = {
|
||||
},
|
||||
|
||||
_getAllCookies() {
|
||||
for (let cookie of Services.cookies.enumerator) {
|
||||
for (let cookie of Services.cookies.cookies) {
|
||||
let site = this._getOrInsertSite(cookie.rawHost);
|
||||
site.cookies.push(cookie);
|
||||
if (site.lastAccessed < cookie.lastAccessed) {
|
||||
@ -371,24 +371,31 @@ var SiteDataManager = {
|
||||
let perms = this._getDeletablePermissions();
|
||||
let promises = [];
|
||||
for (let host of hosts) {
|
||||
const kFlags =
|
||||
Ci.nsIClearDataService.CLEAR_COOKIES |
|
||||
Ci.nsIClearDataService.CLEAR_DOM_STORAGES |
|
||||
Ci.nsIClearDataService.CLEAR_SECURITY_SETTINGS |
|
||||
Ci.nsIClearDataService.CLEAR_PLUGIN_DATA |
|
||||
Ci.nsIClearDataService.CLEAR_EME |
|
||||
Ci.nsIClearDataService.CLEAR_ALL_CACHES;
|
||||
promises.push(
|
||||
new Promise(function(resolve) {
|
||||
Services.clearData.deleteDataFromHost(
|
||||
host,
|
||||
true,
|
||||
Ci.nsIClearDataService.CLEAR_COOKIES |
|
||||
Ci.nsIClearDataService.CLEAR_DOM_STORAGES |
|
||||
Ci.nsIClearDataService.CLEAR_SECURITY_SETTINGS |
|
||||
Ci.nsIClearDataService.CLEAR_PLUGIN_DATA |
|
||||
Ci.nsIClearDataService.CLEAR_EME |
|
||||
Ci.nsIClearDataService.CLEAR_ALL_CACHES,
|
||||
resolve
|
||||
);
|
||||
const { clearData } = Services;
|
||||
if (host) {
|
||||
clearData.deleteDataFromHost(host, true, kFlags, resolve);
|
||||
} else {
|
||||
clearData.deleteDataFromLocalFiles(true, kFlags, resolve);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
for (let perm of perms) {
|
||||
if (Services.eTLD.hasRootDomain(perm.principal.URI.host, host)) {
|
||||
// Specialcase local file permissions.
|
||||
if (!host) {
|
||||
if (perm.principal.URI.schemeIs("file")) {
|
||||
Services.perms.removePermission(perm);
|
||||
}
|
||||
} else if (Services.eTLD.hasRootDomain(perm.principal.URI.host, host)) {
|
||||
Services.perms.removePermission(perm);
|
||||
}
|
||||
}
|
||||
|
@ -128,6 +128,7 @@ XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'AboutNewTab.jsm',
|
||||
'AppUpdater.jsm',
|
||||
'AsyncTabSwitcher.jsm',
|
||||
'BrowserUsageTelemetry.jsm',
|
||||
'BrowserWindowTracker.jsm',
|
||||
|
@ -466,6 +466,51 @@ BasePrincipal::IsSameOrigin(nsIURI* aURI, bool aIsPrivateWin, bool* aRes) {
|
||||
ssm->CheckSameOriginURI(prinURI, aURI, false, aIsPrivateWin));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BasePrincipal::IsL10nAllowed(nsIURI* aURI, bool* aRes) {
|
||||
*aRes = false;
|
||||
|
||||
if (nsContentUtils::IsErrorPage(aURI)) {
|
||||
*aRes = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// The system principal is always allowed.
|
||||
if (IsSystemPrincipal()) {
|
||||
*aRes = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = GetURI(getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, NS_OK);
|
||||
|
||||
bool hasFlags;
|
||||
|
||||
// Allow access to uris that cannot be loaded by web content.
|
||||
rv = NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_DANGEROUS_TO_LOAD,
|
||||
&hasFlags);
|
||||
NS_ENSURE_SUCCESS(rv, NS_OK);
|
||||
if (hasFlags) {
|
||||
*aRes = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// UI resources also get access.
|
||||
rv = NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_IS_UI_RESOURCE,
|
||||
&hasFlags);
|
||||
NS_ENSURE_SUCCESS(rv, NS_OK);
|
||||
if (hasFlags) {
|
||||
*aRes = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
auto policy = AddonPolicy();
|
||||
*aRes = (policy && policy->IsPrivileged());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BasePrincipal::AllowsRelaxStrictFileOriginPolicy(nsIURI* aURI, bool* aRes) {
|
||||
*aRes = false;
|
||||
|
@ -118,6 +118,7 @@ class BasePrincipal : public nsJSPrincipals {
|
||||
NS_IMETHOD GetIsSystemPrincipal(bool* aResult) override;
|
||||
NS_IMETHOD SchemeIs(const char* aScheme, bool* aResult) override;
|
||||
NS_IMETHOD IsURIInPrefList(const char* aPref, bool* aResult) override;
|
||||
NS_IMETHOD IsL10nAllowed(nsIURI* aURI, bool* aResult) override;
|
||||
NS_IMETHOD GetAboutModuleFlags(uint32_t* flags) override;
|
||||
NS_IMETHOD GetIsAddonOrExpandedAddonPrincipal(bool* aResult) override;
|
||||
NS_IMETHOD GetOriginAttributes(JSContext* aCx,
|
||||
|
@ -436,6 +436,12 @@ interface nsIPrincipal : nsISerializable
|
||||
* for the Principals URI
|
||||
*/
|
||||
readonly attribute boolean isScriptAllowedByPolicy;
|
||||
|
||||
/*
|
||||
* Returns true if the Principal can acess l10n
|
||||
* features for the Provided DocumentURI
|
||||
*/
|
||||
boolean isL10nAllowed(in nsIURI aDocumentURI);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "nsChromeRegistryContent.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsError.h"
|
||||
#include "nsEscape.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
@ -1,5 +1,3 @@
|
||||
# -*- Makefile -*-
|
||||
#
|
||||
# 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/.
|
||||
|
@ -10,4 +10,4 @@
|
||||
# hardcoded milestones in the tree from these two files.
|
||||
#--------------------------------------------------------
|
||||
|
||||
68.12.0
|
||||
68.14.2
|
||||
|
@ -51,7 +51,8 @@ function nodeLoadProperties(node: Node, actor) {
|
||||
try {
|
||||
const properties = await loadItemProperties(
|
||||
node,
|
||||
client,
|
||||
client.createObjectClient,
|
||||
client.createLongStringClient,
|
||||
loadedProperties
|
||||
);
|
||||
|
||||
|
@ -37,14 +37,10 @@ import type {
|
||||
Node,
|
||||
} from "../types";
|
||||
|
||||
type Client = {
|
||||
createObjectClient: CreateObjectClient,
|
||||
createLongStringClient: CreateLongStringClient,
|
||||
};
|
||||
|
||||
function loadItemProperties(
|
||||
item: Node,
|
||||
client: Client,
|
||||
createObjectClient: CreateObjectClient,
|
||||
createLongStringClient: CreateLongStringClient,
|
||||
loadedProperties: LoadedProperties
|
||||
): Promise<GripProperties> {
|
||||
const gripItem = getClosestGripNode(item);
|
||||
@ -56,8 +52,7 @@ function loadItemProperties(
|
||||
|
||||
const promises = [];
|
||||
let objectClient;
|
||||
const getObjectClient = () =>
|
||||
objectClient || client.createObjectClient(value);
|
||||
const getObjectClient = () => objectClient || createObjectClient(value);
|
||||
|
||||
if (shouldLoadItemIndexedProperties(item, loadedProperties)) {
|
||||
promises.push(enumIndexedProperties(getObjectClient(), start, end));
|
||||
@ -80,7 +75,7 @@ function loadItemProperties(
|
||||
}
|
||||
|
||||
if (shouldLoadItemFullText(item, loadedProperties)) {
|
||||
promises.push(getFullText(client.createLongStringClient(value), item));
|
||||
promises.push(getFullText(createLongStringClient(value), item));
|
||||
}
|
||||
|
||||
if (shouldLoadItemProxySlots(item, loadedProperties)) {
|
||||
|
@ -69,9 +69,10 @@ function createObjectClient(grip: Grip) {
|
||||
|
||||
async function loadObjectProperties(root: Node) {
|
||||
const utils = Reps.objectInspector.utils;
|
||||
const properties = await utils.loadProperties.loadItemProperties(root, {
|
||||
createObjectClient,
|
||||
});
|
||||
const properties = await utils.loadProperties.loadItemProperties(
|
||||
root,
|
||||
createObjectClient
|
||||
);
|
||||
return utils.node.getChildren({
|
||||
item: root,
|
||||
loadedProperties: new Map([[root.path, properties]]),
|
||||
|
@ -471,6 +471,7 @@ const BLOCKED_REASON_MESSAGES = {
|
||||
4004: "CSP Data Document",
|
||||
4005: "CSP Web Browser",
|
||||
4006: "CSP Preload",
|
||||
5000: "Not same-origin",
|
||||
};
|
||||
|
||||
const general = {
|
||||
|
@ -40,7 +40,7 @@ add_task(async function() {
|
||||
`${method} ${SIMPLE_URL} ${httpVersion}`,
|
||||
"Host: example.com",
|
||||
"User-Agent: " + navigator.userAgent + "",
|
||||
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
||||
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
|
||||
"Accept-Language: " + navigator.languages.join(",") + ";q=0.5",
|
||||
"Accept-Encoding: gzip, deflate",
|
||||
"Connection: keep-alive",
|
||||
|
@ -3928,14 +3928,14 @@ const {
|
||||
nodeIsLongString
|
||||
} = __webpack_require__(114);
|
||||
|
||||
function loadItemProperties(item, client, loadedProperties) {
|
||||
function loadItemProperties(item, createObjectClient, createLongStringClient, loadedProperties) {
|
||||
const gripItem = getClosestGripNode(item);
|
||||
const value = getValue(gripItem);
|
||||
const [start, end] = item.meta ? [item.meta.startIndex, item.meta.endIndex] : [];
|
||||
const promises = [];
|
||||
let objectClient;
|
||||
|
||||
const getObjectClient = () => objectClient || client.createObjectClient(value);
|
||||
const getObjectClient = () => objectClient || createObjectClient(value);
|
||||
|
||||
if (shouldLoadItemIndexedProperties(item, loadedProperties)) {
|
||||
promises.push(enumIndexedProperties(getObjectClient(), start, end));
|
||||
@ -3958,7 +3958,7 @@ function loadItemProperties(item, client, loadedProperties) {
|
||||
}
|
||||
|
||||
if (shouldLoadItemFullText(item, loadedProperties)) {
|
||||
promises.push(getFullText(client.createLongStringClient(value), item));
|
||||
promises.push(getFullText(createLongStringClient(value), item));
|
||||
}
|
||||
|
||||
if (shouldLoadItemProxySlots(item, loadedProperties)) {
|
||||
@ -7923,7 +7923,7 @@ function nodeLoadProperties(node, actor) {
|
||||
}
|
||||
|
||||
try {
|
||||
const properties = await loadItemProperties(node, client, loadedProperties);
|
||||
const properties = await loadItemProperties(node, client.createObjectClient, client.createLongStringClient, loadedProperties);
|
||||
dispatch(nodePropertiesLoaded(node, actor, properties));
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
@ -20,14 +20,14 @@ const {
|
||||
* `a.b.c.d.` is described as ['a', 'b', 'c', 'd'] ).
|
||||
*/
|
||||
function autocompleteUpdate(force, getterPath) {
|
||||
return ({ dispatch, getState, webConsoleUI, hud }) => {
|
||||
if (hud.inputHasSelection()) {
|
||||
return ({ dispatch, getState, services }) => {
|
||||
if (services.inputHasSelection()) {
|
||||
return dispatch(autocompleteClear());
|
||||
}
|
||||
|
||||
const inputValue = hud.getInputValue();
|
||||
const { frameActor: frameActorId, client } = webConsoleUI.getFrameActor();
|
||||
const cursor = webConsoleUI.getInputCursor();
|
||||
const inputValue = services.getInputValue();
|
||||
const { frameActor: frameActorId, client } = services.getFrameActor();
|
||||
const cursor = services.getInputCursor();
|
||||
|
||||
const state = getState().autocomplete;
|
||||
const { cache } = state;
|
||||
@ -131,8 +131,8 @@ function autocompleteDataFetch({
|
||||
client,
|
||||
authorizedEvaluations,
|
||||
}) {
|
||||
return ({ dispatch, webConsoleUI }) => {
|
||||
const selectedNodeActor = webConsoleUI.getSelectedNodeActor();
|
||||
return ({ dispatch, services }) => {
|
||||
const selectedNodeActor = services.getSelectedNodeActor();
|
||||
const id = generateRequestId();
|
||||
dispatch({ type: AUTOCOMPLETE_PENDING_REQUEST, id });
|
||||
client
|
||||
|
@ -11,8 +11,6 @@ const actionModules = [
|
||||
require("./messages"),
|
||||
require("./ui"),
|
||||
require("./notifications"),
|
||||
require("./object"),
|
||||
require("./toolbox"),
|
||||
require("./history"),
|
||||
];
|
||||
|
||||
|
@ -37,9 +37,9 @@ loader.lazyRequireGetter(
|
||||
const HELP_URL = "https://developer.mozilla.org/docs/Tools/Web_Console/Helpers";
|
||||
|
||||
function evaluateExpression(expression) {
|
||||
return async ({ dispatch, webConsoleUI, hud }) => {
|
||||
return async ({ dispatch, services }) => {
|
||||
if (!expression) {
|
||||
expression = hud.getInputSelection() || hud.getInputValue();
|
||||
expression = services.getInputSelection() || services.getInputValue();
|
||||
}
|
||||
if (!expression) {
|
||||
return null;
|
||||
@ -63,7 +63,7 @@ function evaluateExpression(expression) {
|
||||
|
||||
let mappedExpressionRes;
|
||||
try {
|
||||
mappedExpressionRes = await hud.getMappedExpression(expression);
|
||||
mappedExpressionRes = await services.getMappedExpression(expression);
|
||||
} catch (e) {
|
||||
console.warn("Error when calling getMappedExpression", e);
|
||||
}
|
||||
@ -72,21 +72,24 @@ function evaluateExpression(expression) {
|
||||
? mappedExpressionRes.expression
|
||||
: expression;
|
||||
|
||||
const { frameActor, client } = webConsoleUI.getFrameActor();
|
||||
const { frameActor, client } = services.getFrameActor();
|
||||
|
||||
// Even if the evaluation fails,
|
||||
// Even if requestEvaluation rejects (because of webConsoleClient.evaluateJSAsync),
|
||||
// we still need to pass the error response to onExpressionEvaluated.
|
||||
const onSettled = res => res;
|
||||
|
||||
const response = await client
|
||||
.evaluateJSAsync(expression, {
|
||||
frameActor,
|
||||
selectedNodeActor: webConsoleUI.getSelectedNodeActor(),
|
||||
selectedNodeActor: services.getSelectedNodeActor(),
|
||||
mapped: mappedExpressionRes ? mappedExpressionRes.mapped : null,
|
||||
})
|
||||
.then(onSettled, onSettled);
|
||||
|
||||
return dispatch(onExpressionEvaluated(response));
|
||||
return onExpressionEvaluated(response, {
|
||||
dispatch,
|
||||
services,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@ -97,101 +100,81 @@ function evaluateExpression(expression) {
|
||||
* @param {Object} response
|
||||
* The message received from the server.
|
||||
*/
|
||||
function onExpressionEvaluated(response) {
|
||||
return async ({ dispatch, webConsoleUI }) => {
|
||||
if (response.error) {
|
||||
console.error(`Evaluation error`, response.error, ": ", response.message);
|
||||
return;
|
||||
}
|
||||
async function onExpressionEvaluated(response, { dispatch, services } = {}) {
|
||||
if (response.error) {
|
||||
console.error(`Evaluation error`, response.error, ": ", response.message);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the evaluation was a top-level await expression that was rejected, there will
|
||||
// be an uncaught exception reported, so we don't need to do anything.
|
||||
if (response.topLevelAwaitRejected === true) {
|
||||
return;
|
||||
}
|
||||
// If the evaluation was a top-level await expression that was rejected, there will
|
||||
// be an uncaught exception reported, so we don't need to do anything.
|
||||
if (response.topLevelAwaitRejected === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!response.helperResult) {
|
||||
dispatch(messagesActions.messagesAdd([response]));
|
||||
return;
|
||||
}
|
||||
if (!response.helperResult) {
|
||||
dispatch(messagesActions.messagesAdd([response]));
|
||||
return;
|
||||
}
|
||||
|
||||
await dispatch(handleHelperResult(response));
|
||||
};
|
||||
await handleHelperResult(response, { dispatch, services });
|
||||
}
|
||||
|
||||
function handleHelperResult(response) {
|
||||
return async ({ dispatch, hud, webConsoleUI }) => {
|
||||
const result = response.result;
|
||||
const helperResult = response.helperResult;
|
||||
const helperHasRawOutput = !!(helperResult || {}).rawOutput;
|
||||
async function handleHelperResult(response, { dispatch, services }) {
|
||||
const result = response.result;
|
||||
const helperResult = response.helperResult;
|
||||
const helperHasRawOutput = !!(helperResult || {}).rawOutput;
|
||||
|
||||
if (helperResult && helperResult.type) {
|
||||
switch (helperResult.type) {
|
||||
case "clearOutput":
|
||||
dispatch(messagesActions.messagesClear());
|
||||
break;
|
||||
case "clearHistory":
|
||||
dispatch(historyActions.clearHistory());
|
||||
break;
|
||||
case "inspectObject": {
|
||||
const objectActor = helperResult.object;
|
||||
webConsoleUI.inspectObjectActor.bind(webConsoleUI);
|
||||
break;
|
||||
}
|
||||
case "help":
|
||||
hud.openLink(HELP_URL);
|
||||
break;
|
||||
case "copyValueToClipboard":
|
||||
clipboardHelper.copyString(helperResult.value);
|
||||
break;
|
||||
case "screenshotOutput":
|
||||
const { args, value } = helperResult;
|
||||
const screenshotMessages = await saveScreenshot(
|
||||
webConsoleUI.getPanelWindow(),
|
||||
args,
|
||||
value
|
||||
);
|
||||
dispatch(
|
||||
messagesActions.messagesAdd(
|
||||
screenshotMessages.map(message => ({
|
||||
message,
|
||||
type: "logMessage",
|
||||
}))
|
||||
)
|
||||
);
|
||||
// early return as we already dispatched necessary messages.
|
||||
return;
|
||||
}
|
||||
if (helperResult && helperResult.type) {
|
||||
switch (helperResult.type) {
|
||||
case "clearOutput":
|
||||
dispatch(messagesActions.messagesClear());
|
||||
break;
|
||||
case "clearHistory":
|
||||
dispatch(historyActions.clearHistory());
|
||||
break;
|
||||
case "inspectObject":
|
||||
services.inspectObjectActor(helperResult.object);
|
||||
break;
|
||||
case "help":
|
||||
services.openLink(HELP_URL);
|
||||
break;
|
||||
case "copyValueToClipboard":
|
||||
clipboardHelper.copyString(helperResult.value);
|
||||
break;
|
||||
case "screenshotOutput":
|
||||
const { args, value } = helperResult;
|
||||
const screenshotMessages = await saveScreenshot(
|
||||
services.getPanelWindow(),
|
||||
args,
|
||||
value
|
||||
);
|
||||
dispatch(
|
||||
messagesActions.messagesAdd(
|
||||
screenshotMessages.map(message => ({
|
||||
message,
|
||||
type: "logMessage",
|
||||
}))
|
||||
)
|
||||
);
|
||||
// early return as we already dispatched necessary messages.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const hasErrorMessage =
|
||||
response.exceptionMessage ||
|
||||
(helperResult && helperResult.type === "error");
|
||||
const hasErrorMessage =
|
||||
response.exceptionMessage ||
|
||||
(helperResult && helperResult.type === "error");
|
||||
|
||||
// Hide undefined results coming from helper functions.
|
||||
const hasUndefinedResult =
|
||||
result && typeof result == "object" && result.type == "undefined";
|
||||
// Hide undefined results coming from helper functions.
|
||||
const hasUndefinedResult =
|
||||
result && typeof result == "object" && result.type == "undefined";
|
||||
|
||||
if (hasErrorMessage || helperHasRawOutput || !hasUndefinedResult) {
|
||||
dispatch(messagesActions.messagesAdd([response]));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function focusInput() {
|
||||
return ({ hud }) => {
|
||||
return hud.focusInput();
|
||||
};
|
||||
}
|
||||
|
||||
function setInputValue(value) {
|
||||
return ({ hud }) => {
|
||||
return hud.setInputValue(value);
|
||||
};
|
||||
if (hasErrorMessage || helperHasRawOutput || !hasUndefinedResult) {
|
||||
dispatch(messagesActions.messagesAdd([response]));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
evaluateExpression,
|
||||
focusInput,
|
||||
setInputValue,
|
||||
};
|
||||
|
@ -107,26 +107,26 @@ function messageClose(id) {
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
function messageGetMatchingElements(id, cssSelectors) {
|
||||
return async ({ dispatch, client }) => {
|
||||
try {
|
||||
const response = await client.evaluateJSAsync(
|
||||
`document.querySelectorAll('${cssSelectors}')`
|
||||
);
|
||||
dispatch(messageUpdatePayload(id, response.result));
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
return ({ dispatch, services }) => {
|
||||
services
|
||||
.requestEvaluation(`document.querySelectorAll('${cssSelectors}')`)
|
||||
.then(response => {
|
||||
dispatch(messageUpdatePayload(id, response.result));
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function messageGetTableData(id, grip, dataType) {
|
||||
return async ({ dispatch, client }) => {
|
||||
return async ({ dispatch, services }) => {
|
||||
const needEntries = ["Map", "WeakMap", "Set", "WeakSet"].includes(dataType);
|
||||
const enumIndexedPropertiesOnly = getArrayTypeNames().includes(dataType);
|
||||
|
||||
const results = await (needEntries
|
||||
? client.fetchObjectEntries(grip)
|
||||
: client.fetchObjectProperties(grip, enumIndexedPropertiesOnly));
|
||||
? services.fetchObjectEntries(grip)
|
||||
: services.fetchObjectProperties(grip, enumIndexedPropertiesOnly));
|
||||
|
||||
dispatch(messageUpdatePayload(id, results));
|
||||
};
|
||||
@ -170,12 +170,6 @@ function networkUpdateRequest(id, data) {
|
||||
};
|
||||
}
|
||||
|
||||
function jumpToExecutionPoint(executionPoint) {
|
||||
return ({ client }) => {
|
||||
client.timeWarp(executionPoint);
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
messagesAdd,
|
||||
messagesClear,
|
||||
@ -190,5 +184,4 @@ module.exports = {
|
||||
privateMessagesClear,
|
||||
// for test purpose only.
|
||||
setPauseExecutionPoint,
|
||||
jumpToExecutionPoint,
|
||||
};
|
||||
|
@ -10,7 +10,5 @@ DevToolsModules(
|
||||
'input.js',
|
||||
'messages.js',
|
||||
'notifications.js',
|
||||
'object.js',
|
||||
'toolbox.js',
|
||||
'ui.js',
|
||||
)
|
||||
|
@ -1,53 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
loader.lazyServiceGetter(
|
||||
this,
|
||||
"clipboardHelper",
|
||||
"@mozilla.org/widget/clipboardhelper;1",
|
||||
"nsIClipboardHelper"
|
||||
);
|
||||
|
||||
function storeAsGlobal(actor) {
|
||||
return async ({ client, hud }) => {
|
||||
const evalString = `{ let i = 0;
|
||||
while (this.hasOwnProperty("temp" + i) && i < 1000) {
|
||||
i++;
|
||||
}
|
||||
this["temp" + i] = _self;
|
||||
"temp" + i;
|
||||
}`;
|
||||
|
||||
const options = {
|
||||
selectedObjectActor: actor,
|
||||
};
|
||||
|
||||
const res = await client.evaluateJSAsync(evalString, options);
|
||||
hud.focusInput();
|
||||
hud.setInputValue(res.result);
|
||||
};
|
||||
}
|
||||
|
||||
function copyMessageObject(actor, variableText) {
|
||||
return async ({ client }) => {
|
||||
if (actor) {
|
||||
// The Debugger.Object of the OA will be bound to |_self| during evaluation.
|
||||
// See server/actors/webconsole/eval-with-debugger.js `evalWithDebugger`.
|
||||
const res = await client.evaluateJSAsync("copy(_self)", {
|
||||
selectedObjectActor: actor,
|
||||
});
|
||||
|
||||
clipboardHelper.copyString(res.helperResult.value);
|
||||
} else {
|
||||
clipboardHelper.copyString(variableText);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
storeAsGlobal,
|
||||
copyMessageObject,
|
||||
};
|
@ -1,22 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
function openNetworkPanel(messageId) {
|
||||
return ({ hud }) => {
|
||||
hud.openNetworkPanel(messageId);
|
||||
};
|
||||
}
|
||||
|
||||
function resendNetworkRequest(messageId) {
|
||||
return ({ hud }) => {
|
||||
hud.resendNetworkRequest(messageId);
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
openNetworkPanel,
|
||||
resendNetworkRequest,
|
||||
};
|
@ -24,12 +24,6 @@ const {
|
||||
EDITOR_SET_WIDTH,
|
||||
} = require("devtools/client/webconsole/constants");
|
||||
|
||||
function openLink(url, e) {
|
||||
return ({ hud }) => {
|
||||
return hud.openLink(url, e);
|
||||
};
|
||||
}
|
||||
|
||||
function persistToggle() {
|
||||
return ({ dispatch, getState, prefsService }) => {
|
||||
dispatch({
|
||||
@ -155,18 +149,6 @@ function filterBarDisplayModeSet(displayMode) {
|
||||
};
|
||||
}
|
||||
|
||||
function openSidebar(messageId, rootActorId) {
|
||||
return ({ dispatch }) => {
|
||||
dispatch(showMessageObjectInSidebar(rootActorId, messageId));
|
||||
};
|
||||
}
|
||||
|
||||
function timeWarp(executionPoint) {
|
||||
return ({ client }) => {
|
||||
client.timeWarp(executionPoint);
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
contentMessagesToggle,
|
||||
editorToggle,
|
||||
@ -182,7 +164,4 @@ module.exports = {
|
||||
splitConsoleCloseButtonToggle,
|
||||
timestampsToggle,
|
||||
warningGroupsToggle,
|
||||
openLink,
|
||||
openSidebar,
|
||||
timeWarp,
|
||||
};
|
||||
|
@ -1,59 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const ObjectClient = require("devtools/shared/client/object-client");
|
||||
const LongStringClient = require("devtools/shared/client/long-string-client");
|
||||
|
||||
class ConsoleCommands {
|
||||
constructor({ debuggerClient, proxy, threadFront, currentTarget }) {
|
||||
this.debuggerClient = debuggerClient;
|
||||
this.proxy = proxy;
|
||||
this.threadFront = threadFront;
|
||||
this.currentTarget = currentTarget;
|
||||
}
|
||||
|
||||
evaluateJSAsync(expression, options) {
|
||||
return this.proxy.webConsoleClient.evaluateJSAsync(expression, options);
|
||||
}
|
||||
|
||||
createObjectClient(object) {
|
||||
return new ObjectClient(this.debuggerClient, object);
|
||||
}
|
||||
|
||||
createLongStringClient(object) {
|
||||
return new LongStringClient(this.debuggerClient, object);
|
||||
}
|
||||
|
||||
releaseActor(actor) {
|
||||
if (!actor) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.debuggerClient.release(actor);
|
||||
}
|
||||
|
||||
async fetchObjectProperties(grip, ignoreNonIndexedProperties) {
|
||||
const client = new ObjectClient(this.currentTarget.client, grip);
|
||||
const { iterator } = await client.enumProperties({
|
||||
ignoreNonIndexedProperties,
|
||||
});
|
||||
const { ownProperties } = await iterator.slice(0, iterator.count);
|
||||
return ownProperties;
|
||||
}
|
||||
|
||||
async fetchObjectEntries(grip) {
|
||||
const client = new ObjectClient(this.currentTarget.client, grip);
|
||||
const { iterator } = await client.enumEntries();
|
||||
const { ownProperties } = await iterator.slice(0, iterator.count);
|
||||
return ownProperties;
|
||||
}
|
||||
|
||||
timeWarp(executionPoint) {
|
||||
return this.threadFront.timeWarp(executionPoint);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ConsoleCommands;
|
@ -79,7 +79,7 @@ class Message extends Component {
|
||||
timeStamp: PropTypes.number,
|
||||
timestampsVisible: PropTypes.bool.isRequired,
|
||||
serviceContainer: PropTypes.shape({
|
||||
emitEvent: PropTypes.func.isRequired,
|
||||
emitNewMessage: PropTypes.func.isRequired,
|
||||
onViewSource: PropTypes.func.isRequired,
|
||||
onViewSourceInDebugger: PropTypes.func,
|
||||
onViewSourceInScratchpad: PropTypes.func,
|
||||
@ -123,8 +123,15 @@ class Message extends Component {
|
||||
if (this.props.scrollToMessage) {
|
||||
this.messageNode.scrollIntoView();
|
||||
}
|
||||
|
||||
this.emitNewMessage(this.messageNode);
|
||||
// Event used in tests. Some message types don't pass it in because existing tests
|
||||
// did not emit for them.
|
||||
if (this.props.serviceContainer) {
|
||||
this.props.serviceContainer.emitNewMessage(
|
||||
this.messageNode,
|
||||
this.props.messageId,
|
||||
this.props.timeStamp
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,16 +139,6 @@ class Message extends Component {
|
||||
this.setState({ error: e });
|
||||
}
|
||||
|
||||
// Event used in tests. Some message types don't pass it in because existing tests
|
||||
// did not emit for them.
|
||||
emitNewMessage(node) {
|
||||
const { serviceContainer, messageId, timeStamp } = this.props;
|
||||
serviceContainer.emitEvent(
|
||||
"new-messages",
|
||||
new Set([{ node, messageId, timeStamp }])
|
||||
);
|
||||
}
|
||||
|
||||
onLearnMoreClick(e) {
|
||||
const { exceptionDocURL } = this.props;
|
||||
this.props.serviceContainer.openLink(exceptionDocURL, e);
|
||||
@ -178,9 +175,9 @@ class Message extends Component {
|
||||
}
|
||||
|
||||
onMouseEvent(ev) {
|
||||
const { message, serviceContainer, executionPoint } = this.props;
|
||||
const { messageId, serviceContainer, executionPoint } = this.props;
|
||||
if (serviceContainer.canRewind() && executionPoint) {
|
||||
serviceContainer.onMessageHover(ev.type, message);
|
||||
serviceContainer.onMessageHover(ev.type, messageId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,6 @@ DIRS += [
|
||||
DevToolsModules(
|
||||
'browser-console-manager.js',
|
||||
'browser-console.js',
|
||||
'commands.js',
|
||||
'constants.js',
|
||||
'panel.js',
|
||||
'service-container.js',
|
||||
|
@ -4,6 +4,8 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const { getMessage } = require("devtools/client/webconsole/selectors/messages");
|
||||
|
||||
const {
|
||||
createContextMenu,
|
||||
} = require("devtools/client/webconsole/utils/context-menu");
|
||||
@ -12,56 +14,359 @@ const {
|
||||
createEditContextMenu,
|
||||
} = require("devtools/client/framework/toolbox-context-menu");
|
||||
|
||||
const ObjectClient = require("devtools/shared/client/object-client");
|
||||
const LongStringClient = require("devtools/shared/client/long-string-client");
|
||||
loader.lazyRequireGetter(
|
||||
this,
|
||||
"getElementText",
|
||||
"devtools/client/webconsole/utils/clipboard",
|
||||
true
|
||||
);
|
||||
|
||||
// webConsoleUI
|
||||
|
||||
function setupServiceContainer({
|
||||
webConsoleUI,
|
||||
actions,
|
||||
debuggerClient,
|
||||
hud,
|
||||
toolbox,
|
||||
webConsoleWrapper,
|
||||
webconsoleWrapper,
|
||||
}) {
|
||||
const serviceContainer = {
|
||||
openContextMenu: (event, message) =>
|
||||
createContextMenu(event, message, webConsoleWrapper),
|
||||
const attachRefToWebConsoleUI = (id, node) => {
|
||||
webConsoleUI[id] = node;
|
||||
};
|
||||
|
||||
openEditContextMenu: event => {
|
||||
const { screenX, screenY } = event;
|
||||
const menu = createEditContextMenu(window, "webconsole-menu");
|
||||
// Emit the "menu-open" event for testing.
|
||||
menu.once("open", () => webConsoleWrapper.emit("menu-open"));
|
||||
menu.popup(screenX, screenY, hud.chromeWindow.document);
|
||||
const serviceContainer = {
|
||||
attachRefToWebConsoleUI,
|
||||
emitNewMessage: (node, messageId, timeStamp) => {
|
||||
webConsoleUI.emit(
|
||||
"new-messages",
|
||||
new Set([
|
||||
{
|
||||
node,
|
||||
messageId,
|
||||
timeStamp,
|
||||
},
|
||||
])
|
||||
);
|
||||
},
|
||||
openLink: (url, e) => {
|
||||
webConsoleUI.hud.openLink(url, e);
|
||||
},
|
||||
canRewind: () => {
|
||||
if (
|
||||
!(
|
||||
webConsoleUI.hud &&
|
||||
webConsoleUI.hud.target &&
|
||||
webConsoleUI.hud.target.traits
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return webConsoleUI.hud.target.traits.canRewind;
|
||||
},
|
||||
createElement: nodename => {
|
||||
return webconsoleWrapper.document.createElement(nodename);
|
||||
},
|
||||
fetchObjectProperties: async (grip, ignoreNonIndexedProperties) => {
|
||||
const client = new ObjectClient(hud.currentTarget.client, grip);
|
||||
const { iterator } = await client.enumProperties({
|
||||
ignoreNonIndexedProperties,
|
||||
});
|
||||
const { ownProperties } = await iterator.slice(0, iterator.count);
|
||||
return ownProperties;
|
||||
},
|
||||
fetchObjectEntries: async grip => {
|
||||
const client = new ObjectClient(hud.currentTarget.client, grip);
|
||||
const { iterator } = await client.enumEntries();
|
||||
const { ownProperties } = await iterator.slice(0, iterator.count);
|
||||
return ownProperties;
|
||||
},
|
||||
getLongString: grip => {
|
||||
return webConsoleUI.proxy.webConsoleClient.getString(grip);
|
||||
},
|
||||
requestData(id, type) {
|
||||
return webConsoleUI.proxy.networkDataProvider.requestData(id, type);
|
||||
},
|
||||
onViewSource(frame) {
|
||||
if (webConsoleUI && webConsoleUI.hud && webConsoleUI.hud.viewSource) {
|
||||
webConsoleUI.hud.viewSource(frame.url, frame.line);
|
||||
}
|
||||
},
|
||||
recordTelemetryEvent: (eventName, extra = {}) => {
|
||||
webconsoleWrapper.telemetry.recordEvent(eventName, "webconsole", null, {
|
||||
...extra,
|
||||
session_id: (toolbox && toolbox.sessionId) || -1,
|
||||
});
|
||||
},
|
||||
createObjectClient: object => {
|
||||
return new ObjectClient(debuggerClient, object);
|
||||
},
|
||||
createLongStringClient: object => {
|
||||
return new LongStringClient(debuggerClient, object);
|
||||
},
|
||||
|
||||
// NOTE these methods are proxied currently because the
|
||||
// service container is passed down the tree. These methods should eventually
|
||||
// be moved to redux actions.
|
||||
openLink: (url, e) => hud.openLink(url, e),
|
||||
openNodeInInspector: grip => hud.openNodeInInspector(grip),
|
||||
getInputSelection: () => hud.getInputSelection(),
|
||||
onViewSource: frame => hud.viewSource(frame.url, frame.line),
|
||||
resendNetworkRequest: requestId => hud.resendNetworkRequest(requestId),
|
||||
focusInput: () => hud.focusInput(),
|
||||
setInputValue: value => hud.setInputValue(value),
|
||||
canRewind: () => hud.canRewind(),
|
||||
onMessageHover: (type, message) => webConsoleUI.onMessageHover(message),
|
||||
getLongString: grip => webConsoleUI.getLongString(grip),
|
||||
getJsTermTooltipAnchor: () => webConsoleUI.getJsTermTooltipAnchor(),
|
||||
emitEvent: (event, value) => webConsoleUI.emit(event, value),
|
||||
attachRefToWebConsoleUI: (id, node) => webConsoleUI.attachRef(id, node),
|
||||
requestData: (id, type) => webConsoleWrapper.requestData(id, type),
|
||||
createElement: nodename => webConsoleWrapper.createElement(nodename),
|
||||
releaseActor: actor => {
|
||||
if (!actor) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return debuggerClient.release(actor);
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve the FrameActor ID given a frame depth, or the selected one if no
|
||||
* frame depth given.
|
||||
*
|
||||
* @return { frameActor: String|null, client: Object }:
|
||||
* frameActor is the FrameActor ID for the given frame depth
|
||||
* (or the selected frame if it exists), null if no frame was found.
|
||||
* client is the WebConsole client for the thread the frame is
|
||||
* associated with.
|
||||
*/
|
||||
getFrameActor: () => {
|
||||
const state = hud.getDebuggerFrames();
|
||||
if (!state) {
|
||||
return { frameActor: null, client: webConsoleUI.webConsoleClient };
|
||||
}
|
||||
|
||||
const grip = state.frames[state.selected];
|
||||
|
||||
if (!grip) {
|
||||
return { frameActor: null, client: webConsoleUI.webConsoleClient };
|
||||
}
|
||||
|
||||
return {
|
||||
frameActor: grip.actor,
|
||||
client: state.target.activeConsole,
|
||||
};
|
||||
},
|
||||
|
||||
inputHasSelection: () => {
|
||||
const { editor } = webConsoleUI.jsterm || {};
|
||||
return editor && !!editor.getSelection();
|
||||
},
|
||||
|
||||
getInputValue: () => {
|
||||
return hud.getInputValue();
|
||||
},
|
||||
|
||||
getInputSelection: () => {
|
||||
if (!webConsoleUI.jsterm || !webConsoleUI.jsterm.editor) {
|
||||
return null;
|
||||
}
|
||||
return webConsoleUI.jsterm.editor.getSelection();
|
||||
},
|
||||
|
||||
setInputValue: value => {
|
||||
hud.setInputValue(value);
|
||||
},
|
||||
|
||||
focusInput: () => {
|
||||
return webConsoleUI.jsterm && webConsoleUI.jsterm.focus();
|
||||
},
|
||||
|
||||
requestEvaluation: (string, options) => {
|
||||
return webConsoleUI.webConsoleClient.evaluateJSAsync(string, options);
|
||||
},
|
||||
|
||||
getInputCursor: () => {
|
||||
return webConsoleUI.jsterm && webConsoleUI.jsterm.getSelectionStart();
|
||||
},
|
||||
|
||||
getSelectedNodeActor: () => {
|
||||
const inspectorSelection = hud.getInspectorSelection();
|
||||
if (inspectorSelection && inspectorSelection.nodeFront) {
|
||||
return inspectorSelection.nodeFront.actorID;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
getJsTermTooltipAnchor: () => {
|
||||
return webConsoleUI.outputNode.querySelector(".CodeMirror-cursor");
|
||||
},
|
||||
getMappedExpression: hud.getMappedExpression.bind(hud),
|
||||
getPanelWindow: () => webConsoleUI.window,
|
||||
inspectObjectActor: webConsoleUI.inspectObjectActor.bind(webConsoleUI),
|
||||
};
|
||||
|
||||
// Set `openContextMenu` this way so, `serviceContainer` variable
|
||||
// is available in the current scope and we can pass it into
|
||||
// `createContextMenu` method.
|
||||
serviceContainer.openContextMenu = (e, message) => {
|
||||
const { screenX, screenY, target } = e;
|
||||
|
||||
const messageEl = target.closest(".message");
|
||||
const clipboardText = getElementText(messageEl);
|
||||
|
||||
const linkEl = target.closest("a[href]");
|
||||
const url = linkEl && linkEl.href;
|
||||
|
||||
const messageVariable = target.closest(".objectBox");
|
||||
// Ensure that console.group and console.groupCollapsed commands are not captured
|
||||
const variableText =
|
||||
messageVariable &&
|
||||
!messageEl.classList.contains("startGroup") &&
|
||||
!messageEl.classList.contains("startGroupCollapsed")
|
||||
? messageVariable.textContent
|
||||
: null;
|
||||
|
||||
// Retrieve closes actor id from the DOM.
|
||||
const actorEl =
|
||||
target.closest("[data-link-actor-id]") ||
|
||||
target.querySelector("[data-link-actor-id]");
|
||||
const actor = actorEl ? actorEl.dataset.linkActorId : null;
|
||||
|
||||
const rootObjectInspector = target.closest(".object-inspector");
|
||||
const rootActor = rootObjectInspector
|
||||
? rootObjectInspector.querySelector("[data-link-actor-id]")
|
||||
: null;
|
||||
const rootActorId = rootActor ? rootActor.dataset.linkActorId : null;
|
||||
|
||||
const sidebarTogglePref = webconsoleWrapper.getStore().getState().prefs
|
||||
.sidebarToggle;
|
||||
const openSidebar = sidebarTogglePref
|
||||
? messageId => {
|
||||
webconsoleWrapper
|
||||
.getStore()
|
||||
.dispatch(
|
||||
actions.showMessageObjectInSidebar(rootActorId, messageId)
|
||||
);
|
||||
}
|
||||
: null;
|
||||
|
||||
const messageData = getMessage(
|
||||
webconsoleWrapper.getStore().getState(),
|
||||
message.messageId
|
||||
);
|
||||
const executionPoint = messageData && messageData.executionPoint;
|
||||
|
||||
const menu = createContextMenu(
|
||||
webconsoleWrapper.webConsoleUI,
|
||||
webconsoleWrapper.parentNode,
|
||||
{
|
||||
actor,
|
||||
clipboardText,
|
||||
variableText,
|
||||
message,
|
||||
serviceContainer,
|
||||
openSidebar,
|
||||
rootActorId,
|
||||
executionPoint,
|
||||
toolbox: toolbox,
|
||||
url,
|
||||
}
|
||||
);
|
||||
|
||||
// Emit the "menu-open" event for testing.
|
||||
menu.once("open", () => webconsoleWrapper.emit("menu-open"));
|
||||
menu.popup(screenX, screenY, hud.chromeWindow.document);
|
||||
|
||||
return menu;
|
||||
};
|
||||
|
||||
serviceContainer.openEditContextMenu = e => {
|
||||
const { screenX, screenY } = e;
|
||||
const menu = createEditContextMenu(window, "webconsole-menu");
|
||||
// Emit the "menu-open" event for testing.
|
||||
menu.once("open", () => webconsoleWrapper.emit("menu-open"));
|
||||
menu.popup(screenX, screenY, hud.chromeWindow.document);
|
||||
|
||||
return menu;
|
||||
};
|
||||
|
||||
if (toolbox) {
|
||||
const { highlight, unhighlight } = toolbox.getHighlighter(true);
|
||||
|
||||
Object.assign(serviceContainer, {
|
||||
sourceMapService: toolbox.sourceMapURLService,
|
||||
onViewSourceInDebugger: frame => {
|
||||
toolbox
|
||||
.viewSourceInDebugger(
|
||||
frame.url,
|
||||
frame.line,
|
||||
frame.column,
|
||||
frame.sourceId
|
||||
)
|
||||
.then(() => {
|
||||
webconsoleWrapper.telemetry.recordEvent(
|
||||
"jump_to_source",
|
||||
"webconsole",
|
||||
null,
|
||||
{
|
||||
session_id: toolbox.sessionId,
|
||||
}
|
||||
);
|
||||
webconsoleWrapper.webConsoleUI.emit("source-in-debugger-opened");
|
||||
});
|
||||
},
|
||||
onViewSourceInScratchpad: frame =>
|
||||
toolbox.viewSourceInScratchpad(frame.url, frame.line).then(() => {
|
||||
webconsoleWrapper.telemetry.recordEvent(
|
||||
"jump_to_source",
|
||||
"webconsole",
|
||||
null,
|
||||
{
|
||||
session_id: toolbox.sessionId,
|
||||
}
|
||||
);
|
||||
}),
|
||||
onViewSourceInStyleEditor: frame =>
|
||||
toolbox
|
||||
.viewSourceInStyleEditor(frame.url, frame.line, frame.column)
|
||||
.then(() => {
|
||||
webconsoleWrapper.telemetry.recordEvent(
|
||||
"jump_to_source",
|
||||
"webconsole",
|
||||
null,
|
||||
{
|
||||
session_id: toolbox.sessionId,
|
||||
}
|
||||
);
|
||||
}),
|
||||
openNetworkPanel: requestId => {
|
||||
return toolbox.selectTool("netmonitor").then(panel => {
|
||||
return panel.panelWin.Netmonitor.inspectRequest(requestId);
|
||||
});
|
||||
},
|
||||
resendNetworkRequest: requestId => {
|
||||
return toolbox.getNetMonitorAPI().then(api => {
|
||||
return api.resendRequest(requestId);
|
||||
});
|
||||
},
|
||||
sourceMapService: toolbox ? toolbox.sourceMapURLService : null,
|
||||
highlightDomElement: highlight,
|
||||
unHighlightDomElement: unhighlight,
|
||||
openNodeInInspector: async grip => {
|
||||
await this.toolbox.initInspector();
|
||||
const onSelectInspector = toolbox.selectTool(
|
||||
"inspector",
|
||||
"inspect_dom"
|
||||
);
|
||||
const onGripNodeToFront = this.toolbox.walker.gripToNodeFront(grip);
|
||||
const [front, inspector] = await Promise.all([
|
||||
onGripNodeToFront,
|
||||
onSelectInspector,
|
||||
]);
|
||||
|
||||
const onInspectorUpdated = inspector.once("inspector-updated");
|
||||
const onNodeFrontSet = toolbox.selection.setNodeFront(front, {
|
||||
reason: "console",
|
||||
});
|
||||
|
||||
return Promise.all([onNodeFrontSet, onInspectorUpdated]);
|
||||
},
|
||||
jumpToExecutionPoint: executionPoint =>
|
||||
toolbox.threadFront.timeWarp(executionPoint),
|
||||
onViewSourceInDebugger: frame => hud.onViewSourceInDebugger(frame),
|
||||
onViewSourceInStyleEditor: frame => hud.onViewSourceInStyleEditor(frame),
|
||||
onViewSourceInScratchpad: frame => hud.onViewSourceInScratchpad(frame),
|
||||
|
||||
onMessageHover: (type, messageId) => {
|
||||
const message = getMessage(
|
||||
webconsoleWrapper.getStore().getState(),
|
||||
messageId
|
||||
);
|
||||
webconsoleWrapper.webConsoleUI.emit("message-hover", type, message);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -83,10 +83,19 @@ function configureStore(webConsoleUI, options = {}) {
|
||||
}),
|
||||
};
|
||||
|
||||
// Prepare middleware.
|
||||
const services = options.services || {};
|
||||
|
||||
const middleware = applyMiddleware(
|
||||
thunkWithOptions.bind(null, {
|
||||
prefsService,
|
||||
...options.thunkArgs,
|
||||
services,
|
||||
// Needed for the ObjectInspector
|
||||
client: {
|
||||
createObjectClient: services.createObjectClient,
|
||||
createLongStringClient: services.createLongStringClient,
|
||||
releaseActor: services.releaseActor,
|
||||
},
|
||||
}),
|
||||
historyPersistence,
|
||||
eventTelemetry.bind(null, options.telemetry, options.sessionId)
|
||||
|
@ -6,6 +6,7 @@ support-files =
|
||||
code_bundle_invalidmap.js.map
|
||||
code_bundle_nosource.js
|
||||
code_bundle_nosource.js.map
|
||||
cookieSetter.html
|
||||
head.js
|
||||
sjs_cors-test-server.sjs
|
||||
sjs_slow-response-test-server.sjs
|
||||
@ -80,6 +81,7 @@ support-files =
|
||||
test-iframe-wrong-hud-iframe.html
|
||||
test-iframe-wrong-hud.html
|
||||
test-image.png
|
||||
test-image.png^headers^
|
||||
test-ineffective-iframe-sandbox-warning-inner.html
|
||||
test-ineffective-iframe-sandbox-warning-nested1.html
|
||||
test-ineffective-iframe-sandbox-warning-nested2.html
|
||||
|
@ -57,7 +57,7 @@ async function clickFirstStackElement(hud, message, needsExpansion) {
|
||||
return !!frame;
|
||||
});
|
||||
|
||||
const onSourceOpenedInDebugger = once(hud, "source-in-debugger-opened");
|
||||
const onSourceOpenedInDebugger = once(hud.ui, "source-in-debugger-opened");
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" }, frame);
|
||||
await onSourceOpenedInDebugger;
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ async function testOpenInDebugger(hud, toolbox, text) {
|
||||
|
||||
async function checkClickOnNode(hud, toolbox, frameNode) {
|
||||
info("checking click on node location");
|
||||
const onSourceInDebuggerOpened = once(hud, "source-in-debugger-opened");
|
||||
const onSourceInDebuggerOpened = once(hud.ui, "source-in-debugger-opened");
|
||||
EventUtils.sendMouseEvent(
|
||||
{ type: "mousedown" },
|
||||
frameNode.querySelector(".location")
|
||||
|
@ -7,12 +7,13 @@
|
||||
"use strict";
|
||||
requestLongerTimeout(2);
|
||||
|
||||
const TEST_FILE =
|
||||
"browser/devtools/client/webconsole/test/browser/" +
|
||||
"test-trackingprotection-securityerrors.html";
|
||||
const TEST_PATH = "browser/devtools/client/webconsole/test/browser/";
|
||||
const TEST_FILE = TEST_PATH + "test-trackingprotection-securityerrors.html";
|
||||
const TEST_URI = "http://example.com/" + TEST_FILE;
|
||||
const TRACKER_URL = "http://tracking.example.org/";
|
||||
const BLOCKED_URL = `\u201c${TRACKER_URL}\u201d`;
|
||||
const BLOCKED_URL = `\u201c${TRACKER_URL +
|
||||
TEST_PATH +
|
||||
"cookieSetter.html"}\u201d`;
|
||||
|
||||
const COOKIE_BEHAVIOR_PREF = "network.cookie.cookieBehavior";
|
||||
const COOKIE_BEHAVIORS = {
|
||||
|
@ -42,6 +42,16 @@ registerCleanupFunction(function() {
|
||||
pushPref("privacy.trackingprotection.enabled", true);
|
||||
pushPref("devtools.webconsole.groupWarningMessages", true);
|
||||
|
||||
async function cleanUp() {
|
||||
await new Promise(resolve => {
|
||||
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value =>
|
||||
resolve()
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
add_task(cleanUp);
|
||||
|
||||
add_task(async function testContentBlockingMessage() {
|
||||
const { hud, tab, win } = await openNewWindowAndConsole(
|
||||
"http://tracking.example.org/" + TEST_FILE
|
||||
@ -155,6 +165,8 @@ add_task(async function testCookieBlockedByPermissionMessage() {
|
||||
Services.perms.removeFromPrincipal(p, "cookie");
|
||||
});
|
||||
|
||||
add_task(cleanUp);
|
||||
|
||||
/**
|
||||
* Test that storage access blocked messages are grouped by emitting 2 messages.
|
||||
*
|
||||
|
@ -0,0 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<script>
|
||||
"use strict";
|
||||
document.cookie = "name=value";
|
||||
</script>
|
||||
</html>
|
@ -443,7 +443,7 @@ async function checkClickOnNode(
|
||||
) {
|
||||
info("checking click on node location");
|
||||
|
||||
const onSourceInDebuggerOpened = once(hud, "source-in-debugger-opened");
|
||||
const onSourceInDebuggerOpened = once(hud.ui, "source-in-debugger-opened");
|
||||
|
||||
EventUtils.sendMouseEvent(
|
||||
{ type: "click" },
|
||||
|
@ -0,0 +1 @@
|
||||
Set-Cookie: name=value
|
@ -7,7 +7,7 @@
|
||||
<meta charset="utf8">
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="http://tracking.example.org/"></iframe>
|
||||
<iframe src="http://tracking.example.org/browser/devtools/client/webconsole/test/browser/cookieSetter.html"></iframe>
|
||||
<iframe src="http://tracking.example.com/"></iframe>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -6,7 +6,7 @@
|
||||
module.exports = {
|
||||
attachRefToWebConsoleUI: () => {},
|
||||
canRewind: () => false,
|
||||
emitEvent: () => {},
|
||||
emitNewMessage: () => {},
|
||||
proxy: {
|
||||
client: {},
|
||||
releaseActor: actor => console.log("Release actor", actor),
|
||||
|
@ -11,7 +11,6 @@ const { MESSAGE_SOURCE } = require("devtools/client/webconsole/constants");
|
||||
|
||||
const clipboardHelper = require("devtools/shared/platform/clipboard");
|
||||
const { l10n } = require("devtools/client/webconsole/utils/messages");
|
||||
const actions = require("devtools/client/webconsole/actions/index");
|
||||
|
||||
loader.lazyRequireGetter(this, "saveAs", "devtools/shared/DevToolsUtils", true);
|
||||
loader.lazyRequireGetter(
|
||||
@ -30,54 +29,48 @@ loader.lazyRequireGetter(
|
||||
/**
|
||||
* Create a Menu instance for the webconsole.
|
||||
*
|
||||
* @param {Event} context menu event
|
||||
* {Object} message (optional) message object containing metadata such as:
|
||||
* - {String} source
|
||||
* - {String} request
|
||||
* @param {WebConsoleUI} webConsoleUI
|
||||
* The webConsoleUI instance.
|
||||
* @param {Element} parentNode
|
||||
* The container of the new console frontend output wrapper.
|
||||
* @param {Object} options
|
||||
* - {Actions} bound actions
|
||||
* - {WebConsoleWrapper} wrapper instance used for accessing properties like the store
|
||||
* and window.
|
||||
* - {String} actor (optional) actor id to use for context menu actions
|
||||
* - {String} clipboardText (optional) text to "Copy" if no selection is available
|
||||
* - {String} variableText (optional) which is the textual frontend
|
||||
* representation of the variable
|
||||
* - {Object} message (optional) message object containing metadata such as:
|
||||
* - {String} source
|
||||
* - {String} request
|
||||
* - {Function} openSidebar (optional) function that will open the object
|
||||
* inspector sidebar
|
||||
* - {String} rootActorId (optional) actor id for the root object being clicked on
|
||||
* - {Object} executionPoint (optional) when replaying, the execution point where
|
||||
* this message was logged
|
||||
*/
|
||||
function createContextMenu(event, message, webConsoleWrapper) {
|
||||
const { target } = event;
|
||||
const { parentNode, toolbox, hud } = webConsoleWrapper;
|
||||
const store = webConsoleWrapper.getStore();
|
||||
const { dispatch } = store;
|
||||
|
||||
const messageEl = target.closest(".message");
|
||||
const clipboardText = getElementText(messageEl);
|
||||
|
||||
const linkEl = target.closest("a[href]");
|
||||
const url = linkEl && linkEl.href;
|
||||
|
||||
const messageVariable = target.closest(".objectBox");
|
||||
// Ensure that console.group and console.groupCollapsed commands are not captured
|
||||
const variableText =
|
||||
messageVariable &&
|
||||
!messageEl.classList.contains("startGroup") &&
|
||||
!messageEl.classList.contains("startGroupCollapsed")
|
||||
? messageVariable.textContent
|
||||
: null;
|
||||
|
||||
// Retrieve closes actor id from the DOM.
|
||||
const actorEl =
|
||||
target.closest("[data-link-actor-id]") ||
|
||||
target.querySelector("[data-link-actor-id]");
|
||||
const actor = actorEl ? actorEl.dataset.linkActorId : null;
|
||||
|
||||
const rootObjectInspector = target.closest(".object-inspector");
|
||||
const rootActor = rootObjectInspector
|
||||
? rootObjectInspector.querySelector("[data-link-actor-id]")
|
||||
: null;
|
||||
const rootActorId = rootActor ? rootActor.dataset.linkActorId : null;
|
||||
|
||||
function createContextMenu(
|
||||
webConsoleUI,
|
||||
parentNode,
|
||||
{
|
||||
actor,
|
||||
clipboardText,
|
||||
variableText,
|
||||
message,
|
||||
serviceContainer,
|
||||
openSidebar,
|
||||
rootActorId,
|
||||
executionPoint,
|
||||
toolbox,
|
||||
url,
|
||||
}
|
||||
) {
|
||||
const win = parentNode.ownerDocument.defaultView;
|
||||
const selection = win.getSelection();
|
||||
|
||||
const { source, request, executionPoint, messageId } = message || {};
|
||||
const { source, request } = message || {};
|
||||
|
||||
const menu = new Menu({ id: "webconsole-menu" });
|
||||
const menu = new Menu({
|
||||
id: "webconsole-menu",
|
||||
});
|
||||
|
||||
// Copy URL for a network request.
|
||||
menu.append(
|
||||
@ -96,20 +89,20 @@ function createContextMenu(event, message, webConsoleWrapper) {
|
||||
);
|
||||
|
||||
// Open Network message in the Network panel.
|
||||
if (toolbox && request) {
|
||||
if (serviceContainer.openNetworkPanel && request) {
|
||||
menu.append(
|
||||
new MenuItem({
|
||||
id: "console-menu-open-in-network-panel",
|
||||
label: l10n.getStr("webconsole.menu.openInNetworkPanel.label"),
|
||||
accesskey: l10n.getStr("webconsole.menu.openInNetworkPanel.accesskey"),
|
||||
visible: source === MESSAGE_SOURCE.NETWORK,
|
||||
click: () => dispatch(actions.openNetworkPanel(message.messageId)),
|
||||
click: () => serviceContainer.openNetworkPanel(message.messageId),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// Resend Network message.
|
||||
if (toolbox && request) {
|
||||
if (serviceContainer.resendNetworkRequest && request) {
|
||||
menu.append(
|
||||
new MenuItem({
|
||||
id: "console-menu-resend-network-request",
|
||||
@ -118,7 +111,7 @@ function createContextMenu(event, message, webConsoleWrapper) {
|
||||
"webconsole.menu.resendNetworkRequest.accesskey"
|
||||
),
|
||||
visible: source === MESSAGE_SOURCE.NETWORK,
|
||||
click: () => dispatch(actions.resendNetworkRequest(messageId)),
|
||||
click: () => serviceContainer.resendNetworkRequest(message.messageId),
|
||||
})
|
||||
);
|
||||
}
|
||||
@ -146,7 +139,25 @@ function createContextMenu(event, message, webConsoleWrapper) {
|
||||
label: l10n.getStr("webconsole.menu.storeAsGlobalVar.label"),
|
||||
accesskey: l10n.getStr("webconsole.menu.storeAsGlobalVar.accesskey"),
|
||||
disabled: !actor,
|
||||
click: () => dispatch(actions.storeAsGlobal(actor)),
|
||||
click: () => {
|
||||
const evalString = `{ let i = 0;
|
||||
while (this.hasOwnProperty("temp" + i) && i < 1000) {
|
||||
i++;
|
||||
}
|
||||
this["temp" + i] = _self;
|
||||
"temp" + i;
|
||||
}`;
|
||||
const options = {
|
||||
selectedObjectActor: actor,
|
||||
};
|
||||
|
||||
webConsoleUI.webConsoleClient
|
||||
.evaluateJSAsync(evalString, options)
|
||||
.then(res => {
|
||||
webConsoleUI.jsterm.focus();
|
||||
webConsoleUI.hud.setInputValue(res.result);
|
||||
});
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
@ -178,7 +189,19 @@ function createContextMenu(event, message, webConsoleWrapper) {
|
||||
accesskey: l10n.getStr("webconsole.menu.copyObject.accesskey"),
|
||||
// Disabled if there is no actor and no variable text associated.
|
||||
disabled: !actor && !variableText,
|
||||
click: () => dispatch(actions.copyMessageObject(actor, variableText)),
|
||||
click: () => {
|
||||
if (actor) {
|
||||
// The Debugger.Object of the OA will be bound to |_self| during evaluation.
|
||||
// See server/actors/webconsole/eval-with-debugger.js `evalWithDebugger`.
|
||||
webConsoleUI.webConsoleClient
|
||||
.evaluateJSAsync("copy(_self)", { selectedObjectActor: actor })
|
||||
.then(res => {
|
||||
clipboardHelper.copyString(res.helperResult.value);
|
||||
});
|
||||
} else {
|
||||
clipboardHelper.copyString(variableText);
|
||||
}
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
@ -243,15 +266,14 @@ function createContextMenu(event, message, webConsoleWrapper) {
|
||||
);
|
||||
|
||||
// Open object in sidebar.
|
||||
const shouldOpenSidebar = store.getState().prefs.sidebarToggle;
|
||||
if (shouldOpenSidebar) {
|
||||
if (openSidebar) {
|
||||
menu.append(
|
||||
new MenuItem({
|
||||
id: "console-menu-open-sidebar",
|
||||
label: l10n.getStr("webconsole.menu.openInSidebar.label"),
|
||||
accesskey: l10n.getStr("webconsole.menu.openInSidebar.accesskey"),
|
||||
disabled: !rootActorId,
|
||||
click: () => dispatch(actions.openSidebar(messageId, rootActorId)),
|
||||
click: () => openSidebar(message.messageId),
|
||||
})
|
||||
);
|
||||
}
|
||||
@ -263,7 +285,10 @@ function createContextMenu(event, message, webConsoleWrapper) {
|
||||
id: "console-menu-time-warp",
|
||||
label: l10n.getStr("webconsole.menu.timeWarp.label"),
|
||||
disabled: false,
|
||||
click: () => dispatch(actions.jumpToExecutionPoint(executionPoint)),
|
||||
click: () => {
|
||||
const threadFront = toolbox.threadFront;
|
||||
threadFront.timeWarp(executionPoint);
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
@ -279,11 +304,6 @@ function createContextMenu(event, message, webConsoleWrapper) {
|
||||
);
|
||||
}
|
||||
|
||||
// Emit the "menu-open" event for testing.
|
||||
const { screenX, screenY } = event;
|
||||
menu.once("open", () => webConsoleWrapper.emit("menu-open"));
|
||||
menu.popup(screenX, screenY, hud.chromeWindow.document);
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,6 @@ class WebConsoleUI {
|
||||
this.hud = hud;
|
||||
this.hudId = this.hud.hudId;
|
||||
this.isBrowserConsole = this.hud._browserConsole;
|
||||
|
||||
this.isBrowserToolboxConsole =
|
||||
this.hud.currentTarget &&
|
||||
this.hud.currentTarget.isParentProcess &&
|
||||
@ -180,10 +179,6 @@ class WebConsoleUI {
|
||||
return this.wrapper;
|
||||
}
|
||||
|
||||
getPanelWindow() {
|
||||
return this.window;
|
||||
}
|
||||
|
||||
logWarningAboutReplacedAPI() {
|
||||
return this.hud.target.logWarningInPage(
|
||||
l10n.getStr("ConsoleAPIDisabled"),
|
||||
@ -361,10 +356,6 @@ class WebConsoleUI {
|
||||
}
|
||||
}
|
||||
|
||||
getLongString(grip) {
|
||||
return this.getProxy().webConsoleClient.getString(grip);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the focus to JavaScript input field when the web console tab is
|
||||
* selected or when there is a split console present.
|
||||
@ -404,58 +395,6 @@ class WebConsoleUI {
|
||||
handleTabWillNavigate(packet) {
|
||||
this.wrapper.dispatchTabWillNavigate(packet);
|
||||
}
|
||||
|
||||
getInputCursor() {
|
||||
return this.jsterm && this.jsterm.getSelectionStart();
|
||||
}
|
||||
|
||||
getJsTermTooltipAnchor() {
|
||||
return this.outputNode.querySelector(".CodeMirror-cursor");
|
||||
}
|
||||
|
||||
attachRef(id, node) {
|
||||
this[id] = node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the FrameActor ID given a frame depth, or the selected one if no
|
||||
* frame depth given.
|
||||
*
|
||||
* @return { frameActor: String|null, client: Object }:
|
||||
* frameActor is the FrameActor ID for the given frame depth
|
||||
* (or the selected frame if it exists), null if no frame was found.
|
||||
* client is the WebConsole client for the thread the frame is
|
||||
* associated with.
|
||||
*/
|
||||
getFrameActor() {
|
||||
const state = this.hud.getDebuggerFrames();
|
||||
if (!state) {
|
||||
return { frameActor: null, client: this.webConsoleClient };
|
||||
}
|
||||
|
||||
const grip = state.frames[state.selected];
|
||||
|
||||
if (!grip) {
|
||||
return { frameActor: null, client: this.webConsoleClient };
|
||||
}
|
||||
|
||||
return {
|
||||
frameActor: grip.actor,
|
||||
client: state.target.activeConsole,
|
||||
};
|
||||
}
|
||||
|
||||
getSelectedNodeActor() {
|
||||
const inspectorSelection = this.hud.getInspectorSelection();
|
||||
if (inspectorSelection && inspectorSelection.nodeFront) {
|
||||
return inspectorSelection.nodeFront.actorID;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
onMessageHover(type, message) {
|
||||
this.emit("message-hover", type, message);
|
||||
}
|
||||
}
|
||||
|
||||
/* This is the same as DevelopmentHelpers.quickRestart, but it runs in all
|
||||
|
@ -26,8 +26,6 @@ const Telemetry = require("devtools/client/shared/telemetry");
|
||||
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const App = createFactory(require("devtools/client/webconsole/components/App"));
|
||||
const ConsoleCommands = require("devtools/client/webconsole/commands.js");
|
||||
|
||||
const {
|
||||
setupServiceContainer,
|
||||
} = require("devtools/client/webconsole/service-container");
|
||||
@ -73,29 +71,20 @@ class WebConsoleWrapper {
|
||||
const { webConsoleUI } = this;
|
||||
const debuggerClient = this.hud.target.client;
|
||||
|
||||
const commands = new ConsoleCommands({
|
||||
const serviceContainer = setupServiceContainer({
|
||||
debuggerClient,
|
||||
proxy: webConsoleUI.proxy,
|
||||
threadFront: this.toolbox && this.toolbox.threadFront,
|
||||
currentTarget: this.hud.currentTarget,
|
||||
webConsoleUI,
|
||||
actions,
|
||||
toolbox: this.toolbox,
|
||||
hud: this.hud,
|
||||
webconsoleWrapper: this,
|
||||
});
|
||||
|
||||
store = configureStore(this.webConsoleUI, {
|
||||
// We may not have access to the toolbox (e.g. in the browser console).
|
||||
sessionId: (this.toolbox && this.toolbox.sessionId) || -1,
|
||||
telemetry: this.telemetry,
|
||||
thunkArgs: {
|
||||
webConsoleUI,
|
||||
hud: this.hud,
|
||||
client: commands,
|
||||
},
|
||||
});
|
||||
|
||||
const serviceContainer = setupServiceContainer({
|
||||
webConsoleUI,
|
||||
toolbox: this.toolbox,
|
||||
hud: this.hud,
|
||||
webConsoleWrapper: this,
|
||||
services: serviceContainer,
|
||||
});
|
||||
|
||||
if (this.toolbox) {
|
||||
@ -339,10 +328,6 @@ class WebConsoleWrapper {
|
||||
this.setTimeoutIfNeeded();
|
||||
}
|
||||
|
||||
requestData(id, type) {
|
||||
this.networkDataProvider.requestData(id, type);
|
||||
}
|
||||
|
||||
dispatchClearLogpointMessages(logpointId) {
|
||||
store.dispatch(actions.messagesClearLogpoint(logpointId));
|
||||
}
|
||||
@ -439,10 +424,6 @@ class WebConsoleWrapper {
|
||||
store.subscribe(() => callback(store.getState()));
|
||||
}
|
||||
|
||||
createElement(nodename) {
|
||||
return this.document.createElement(nodename);
|
||||
}
|
||||
|
||||
// Called by pushing close button.
|
||||
closeSplitConsole() {
|
||||
this.toolbox.closeSplitConsole();
|
||||
|
@ -122,19 +122,6 @@ class WebConsole {
|
||||
return this.ui ? this.ui.jsterm : null;
|
||||
}
|
||||
|
||||
canRewind() {
|
||||
if (
|
||||
!(
|
||||
this.hud &&
|
||||
this.hud.target &&
|
||||
this.hud.target.traits
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return this.hud.target.traits.canRewind;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value from the input field.
|
||||
* @returns {String|null} returns null if there's no input.
|
||||
@ -147,18 +134,6 @@ class WebConsole {
|
||||
return this.jsterm._getValue();
|
||||
}
|
||||
|
||||
inputHasSelection() {
|
||||
const { editor } = this.jsterm || {};
|
||||
return editor && !!editor.getSelection();
|
||||
}
|
||||
|
||||
getInputSelection() {
|
||||
if (!this.jsterm || !this.jsterm.editor) {
|
||||
return null;
|
||||
}
|
||||
return this.jsterm.editor.getSelection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the input field (command line)
|
||||
*
|
||||
@ -172,10 +147,6 @@ class WebConsole {
|
||||
this.jsterm._setValue(newValue);
|
||||
}
|
||||
|
||||
focusInput() {
|
||||
return this.jsterm && this.jsterm.focus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a link in a new tab.
|
||||
*
|
||||
@ -239,15 +210,17 @@ class WebConsole {
|
||||
* @param integer sourceColumn
|
||||
* The column number which you want to place the caret.
|
||||
*/
|
||||
async viewSourceInDebugger(sourceURL, sourceLine, sourceColumn) {
|
||||
viewSourceInDebugger(sourceURL, sourceLine, sourceColumn) {
|
||||
const toolbox = gDevTools.getToolbox(this.target);
|
||||
if (!toolbox) {
|
||||
this.viewSource(sourceURL, sourceLine, sourceColumn);
|
||||
return;
|
||||
}
|
||||
|
||||
await toolbox.viewSourceInDebugger(sourceURL, sourceLine, sourceColumn);
|
||||
this.ui.emit("source-in-debugger-opened");
|
||||
toolbox
|
||||
.viewSourceInDebugger(sourceURL, sourceLine, sourceColumn)
|
||||
.then(() => {
|
||||
this.ui.emit("source-in-debugger-opened");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -370,77 +343,6 @@ class WebConsole {
|
||||
return panel.selection;
|
||||
}
|
||||
|
||||
async onViewSourceInDebugger(frame) {
|
||||
if (this.toolbox) {
|
||||
await this.toolbox.viewSourceInDebugger(
|
||||
frame.url,
|
||||
frame.line,
|
||||
frame.column,
|
||||
frame.sourceId
|
||||
);
|
||||
|
||||
this.emit("source-in-debugger-opened");
|
||||
}
|
||||
}
|
||||
|
||||
async onViewSourceInScratchpad(frame) {
|
||||
if (this.toolbox) {
|
||||
await this.toolbox.viewSourceInScratchpad(frame.url, frame.line);
|
||||
}
|
||||
}
|
||||
|
||||
async onViewSourceInStyleEditor(frame) {
|
||||
if (!this.toolbox) {
|
||||
return;
|
||||
}
|
||||
await this.toolbox.viewSourceInStyleEditor(
|
||||
frame.url,
|
||||
frame.line,
|
||||
frame.column
|
||||
);
|
||||
}
|
||||
|
||||
async openNetworkPanel(requestId) {
|
||||
if (!this.toolbox) {
|
||||
return;
|
||||
}
|
||||
const netmonitor = await this.toolbox.selectTool("netmonitor");
|
||||
await netmonitor.panelWin.Netmonitor.inspectRequest(requestId);
|
||||
}
|
||||
|
||||
async resendNetworkRequest(requestId) {
|
||||
if (!this.toolbox) {
|
||||
return;
|
||||
}
|
||||
|
||||
const api = await this.toolbox.getNetMonitorAPI();
|
||||
await api.resendRequest(requestId);
|
||||
}
|
||||
|
||||
async openNodeInInspector(grip) {
|
||||
if (!this.toolbox) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.toolbox.initInspector();
|
||||
const onSelectInspector = this.toolbox.selectTool(
|
||||
"inspector",
|
||||
"inspect_dom"
|
||||
);
|
||||
const onGripNodeToFront = this.toolbox.walker.gripToNodeFront(grip);
|
||||
const [front, inspector] = await Promise.all([
|
||||
onGripNodeToFront,
|
||||
onSelectInspector,
|
||||
]);
|
||||
|
||||
const onInspectorUpdated = inspector.once("inspector-updated");
|
||||
const onNodeFrontSet = this.toolbox.selection.setNodeFront(front, {
|
||||
reason: "console",
|
||||
});
|
||||
|
||||
await Promise.all([onNodeFrontSet, onInspectorUpdated]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the object. Call this method to avoid memory leaks when the Web
|
||||
* Console is closed.
|
||||
|
@ -378,7 +378,7 @@ NetworkResponseListener.prototype = {
|
||||
* Handle progress event as data is transferred. This is used to record the
|
||||
* size on the wire, which may be compressed / encoded.
|
||||
*/
|
||||
onProgress: function(request, context, progress, progressMax) {
|
||||
onProgress: function(request, progress, progressMax) {
|
||||
this.transferredSize = progress;
|
||||
// Need to forward as well to keep things like Download Manager's progress
|
||||
// bar working properly.
|
||||
|
@ -848,9 +848,7 @@ var cookieHelpers = {
|
||||
|
||||
host = trimHttpHttpsPort(host);
|
||||
|
||||
return Array.from(
|
||||
Services.cookies.getCookiesFromHost(host, originAttributes)
|
||||
);
|
||||
return Services.cookies.getCookiesFromHost(host, originAttributes);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -11505,9 +11505,9 @@ nsresult nsDocShell::AddToSessionHistory(
|
||||
// For now keep storing just the principal in the SHEntry.
|
||||
if (!principalToInherit) {
|
||||
if (loadInfo->GetLoadingSandboxed()) {
|
||||
if (loadInfo->LoadingPrincipal()) {
|
||||
if (loadInfo->GetLoadingPrincipal()) {
|
||||
principalToInherit = NullPrincipal::CreateWithInheritedAttributes(
|
||||
loadInfo->LoadingPrincipal());
|
||||
loadInfo->GetLoadingPrincipal());
|
||||
} else {
|
||||
// get the OriginAttributes
|
||||
OriginAttributes attrs;
|
||||
|
@ -61,6 +61,7 @@
|
||||
#include "mozilla/TransactionManager.h" // for TransactionManager
|
||||
#include "mozilla/Tuple.h"
|
||||
#include "mozilla/dom/AbstractRange.h" // for AbstractRange
|
||||
#include "mozilla/dom/Attr.h" // for Attr
|
||||
#include "mozilla/dom/CharacterData.h" // for CharacterData
|
||||
#include "mozilla/dom/DataTransfer.h" // for DataTransfer
|
||||
#include "mozilla/dom/Element.h" // for Element, nsINode::AsElement
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "mozilla/TextServicesDocument.h"
|
||||
#include "mozilla/css/Loader.h"
|
||||
#include "mozilla/dom/AncestorIterator.h"
|
||||
#include "mozilla/dom/Attr.h"
|
||||
#include "mozilla/dom/DocumentFragment.h"
|
||||
#include "mozilla/dom/DocumentInlines.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "nsIDNSRecord.h"
|
||||
#include "nsMemory.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsICryptoHash.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user