68.14.2 - everything else

This commit is contained in:
Fedor 2024-06-01 19:28:12 +03:00
parent 40ed9513e6
commit 0ed4d27300
864 changed files with 53758 additions and 53143 deletions

View File

@ -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");

View File

@ -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([

View File

@ -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)

View 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",
]),
};

View File

@ -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;
})();

View File

@ -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;
},

View File

@ -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",

View File

@ -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 = {

View File

@ -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");

View File

@ -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>

View File

@ -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]

View File

@ -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);
});
}

View File

@ -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 }
);
});
}

View File

@ -1,2 +0,0 @@
CACHE MANIFEST
gZipOfflineChild.html

View File

@ -1 +0,0 @@
Content-Type: text/cache-manifest

View File

@ -1,2 +0,0 @@
Content-Type: text/html
Content-Encoding: gzip

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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]

View File

@ -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");
});

View File

@ -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,

View File

@ -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)

View File

@ -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");
}
});

View File

@ -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");
}
}

View File

@ -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");
}
});

View File

@ -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.

View File

@ -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
);

View File

@ -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)) &&

View File

@ -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);
});

View File

@ -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) {

View File

@ -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();
});

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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(

View File

@ -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",

View File

@ -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;
},
};

View File

@ -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");

View File

@ -194,7 +194,7 @@ var SessionCookiesInternal = {
return;
}
for (let cookie of Services.cookies.sessionEnumerator) {
for (let cookie of Services.cookies.sessionCookies) {
this._addCookie(cookie);
}
},

View File

@ -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;
}

View File

@ -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"

View File

@ -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;
},

View File

@ -1 +1 @@
68.14.1
68.14.2

View File

@ -1 +1 @@
68.14.1b
68.14.2b

Binary file not shown.

View File

@ -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

View File

@ -430,10 +430,6 @@ offlineApps.allowStoring.accesskey=A
offlineApps.dontAllow.label=Dont 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.

View 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,
};

View File

@ -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;
}

View File

@ -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)

View File

@ -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);
}
}

View File

@ -128,6 +128,7 @@ XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
EXTRA_JS_MODULES += [
'AboutNewTab.jsm',
'AppUpdater.jsm',
'AsyncTabSwitcher.jsm',
'BrowserUsageTelemetry.jsm',
'BrowserWindowTracker.jsm',

View File

@ -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;

View File

@ -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,

View File

@ -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);
};
/**

View File

@ -7,6 +7,7 @@
#include "nsChromeRegistryContent.h"
#include "nsCOMPtr.h"
#include "nsComponentManagerUtils.h"
#include "nsError.h"
#include "nsEscape.h"
#include "nsNetUtil.h"

View File

@ -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/.

View File

@ -10,4 +10,4 @@
# hardcoded milestones in the tree from these two files.
#--------------------------------------------------------
68.12.0
68.14.2

View File

@ -51,7 +51,8 @@ function nodeLoadProperties(node: Node, actor) {
try {
const properties = await loadItemProperties(
node,
client,
client.createObjectClient,
client.createLongStringClient,
loadedProperties
);

View File

@ -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)) {

View File

@ -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]]),

View File

@ -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 = {

View File

@ -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",

View File

@ -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);

View File

@ -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

View File

@ -11,8 +11,6 @@ const actionModules = [
require("./messages"),
require("./ui"),
require("./notifications"),
require("./object"),
require("./toolbox"),
require("./history"),
];

View File

@ -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,
};

View File

@ -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,
};

View File

@ -10,7 +10,5 @@ DevToolsModules(
'input.js',
'messages.js',
'notifications.js',
'object.js',
'toolbox.js',
'ui.js',
)

View File

@ -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,
};

View File

@ -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,
};

View File

@ -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,
};

View File

@ -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;

View File

@ -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);
}
}

View File

@ -15,7 +15,6 @@ DIRS += [
DevToolsModules(
'browser-console-manager.js',
'browser-console.js',
'commands.js',
'constants.js',
'panel.js',
'service-container.js',

View File

@ -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);
},
});
}

View File

@ -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)

View File

@ -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

View File

@ -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;
}

View File

@ -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")

View File

@ -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 = {

View File

@ -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.
*

View File

@ -0,0 +1,7 @@
<!DOCTYPE html>
<html>
<script>
"use strict";
document.cookie = "name=value";
</script>
</html>

View File

@ -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" },

View File

@ -0,0 +1 @@
Set-Cookie: name=value

View File

@ -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>

View File

@ -6,7 +6,7 @@
module.exports = {
attachRefToWebConsoleUI: () => {},
canRewind: () => false,
emitEvent: () => {},
emitNewMessage: () => {},
proxy: {
client: {},
releaseActor: actor => console.log("Release actor", actor),

View File

@ -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;
}

View File

@ -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

View File

@ -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();

View File

@ -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.

View File

@ -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.

View File

@ -848,9 +848,7 @@ var cookieHelpers = {
host = trimHttpHttpsPort(host);
return Array.from(
Services.cookies.getCookiesFromHost(host, originAttributes)
);
return Services.cookies.getCookiesFromHost(host, originAttributes);
},
/**

View File

@ -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;

View File

@ -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

View File

@ -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"

View File

@ -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