зеркало из https://github.com/mozilla/gecko-dev.git
merge fx-team to mozilla-central a=merge
This commit is contained in:
Коммит
943c4b4489
|
@ -1407,7 +1407,6 @@ pref("devtools.tilt.outro_transition", true);
|
|||
// - enableAutocompletion: Whether to enable JavaScript autocompletion.
|
||||
pref("devtools.scratchpad.recentFilesMax", 10);
|
||||
pref("devtools.scratchpad.showTrailingSpace", false);
|
||||
pref("devtools.scratchpad.enableCodeFolding", true);
|
||||
pref("devtools.scratchpad.enableAutocompletion", true);
|
||||
|
||||
// Enable the Storage Inspector
|
||||
|
@ -1513,6 +1512,7 @@ pref("devtools.editor.expandtab", true);
|
|||
pref("devtools.editor.keymap", "default");
|
||||
pref("devtools.editor.autoclosebrackets", true);
|
||||
pref("devtools.editor.detectindentation", true);
|
||||
pref("devtools.editor.enableCodeFolding", true);
|
||||
pref("devtools.editor.autocomplete", true);
|
||||
|
||||
// Enable the Font Inspector
|
||||
|
|
|
@ -233,7 +233,8 @@ let DebuggerView = {
|
|||
showAnnotationRuler: true,
|
||||
gutters: gutters,
|
||||
extraKeys: extraKeys,
|
||||
contextMenu: "sourceEditorContextMenu"
|
||||
contextMenu: "sourceEditorContextMenu",
|
||||
enableCodeFolding: false
|
||||
});
|
||||
|
||||
this.editor.appendTo(document.getElementById("editor")).then(() => {
|
||||
|
|
|
@ -34,8 +34,8 @@ const SCRATCHPAD_L10N = "chrome://browser/locale/devtools/scratchpad.properties"
|
|||
const DEVTOOLS_CHROME_ENABLED = "devtools.chrome.enabled";
|
||||
const PREF_RECENT_FILES_MAX = "devtools.scratchpad.recentFilesMax";
|
||||
const SHOW_TRAILING_SPACE = "devtools.scratchpad.showTrailingSpace";
|
||||
const ENABLE_CODE_FOLDING = "devtools.scratchpad.enableCodeFolding";
|
||||
const ENABLE_AUTOCOMPLETION = "devtools.scratchpad.enableAutocompletion";
|
||||
const TAB_SIZE = "devtools.editor.tabsize";
|
||||
|
||||
const VARIABLES_VIEW_URL = "chrome://browser/content/devtools/widgets/VariablesView.xul";
|
||||
|
||||
|
@ -655,7 +655,7 @@ var Scratchpad = {
|
|||
*/
|
||||
prettyPrint: function SP_prettyPrint() {
|
||||
const uglyText = this.getText();
|
||||
const tabsize = Services.prefs.getIntPref("devtools.editor.tabsize");
|
||||
const tabsize = Services.prefs.getIntPref(TAB_SIZE);
|
||||
const id = Math.random();
|
||||
const deferred = promise.defer();
|
||||
|
||||
|
@ -1604,7 +1604,6 @@ var Scratchpad = {
|
|||
lineNumbers: true,
|
||||
contextMenu: "scratchpad-text-popup",
|
||||
showTrailingSpace: Services.prefs.getBoolPref(SHOW_TRAILING_SPACE),
|
||||
enableCodeFolding: Services.prefs.getBoolPref(ENABLE_CODE_FOLDING),
|
||||
autocomplete: Services.prefs.getBoolPref(ENABLE_AUTOCOMPLETION),
|
||||
};
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
const { Cu, Cc, Ci, components } = require("chrome");
|
||||
|
||||
const TAB_SIZE = "devtools.editor.tabsize";
|
||||
const ENABLE_CODE_FOLDING = "devtools.editor.enableCodeFolding";
|
||||
const EXPAND_TAB = "devtools.editor.expandtab";
|
||||
const KEYMAP = "devtools.editor.keymap";
|
||||
const AUTO_CLOSE = "devtools.editor.autoclosebrackets";
|
||||
|
@ -188,14 +189,12 @@ function Editor(config) {
|
|||
});
|
||||
});
|
||||
|
||||
// Set the code folding gutter, if needed.
|
||||
if (this.config.enableCodeFolding) {
|
||||
this.config.foldGutter = true;
|
||||
|
||||
if (!this.config.gutters) {
|
||||
this.config.gutters = this.config.lineNumbers ? ["CodeMirror-linenumbers"] : [];
|
||||
this.config.gutters.push("CodeMirror-foldgutter");
|
||||
}
|
||||
if (!this.config.gutters) {
|
||||
this.config.gutters = [];
|
||||
}
|
||||
if (this.config.lineNumbers
|
||||
&& this.config.gutters.indexOf("CodeMirror-linenumbers") === -1) {
|
||||
this.config.gutters.push("CodeMirror-linenumbers");
|
||||
}
|
||||
|
||||
// Remember the initial value of autoCloseBrackets.
|
||||
|
@ -333,6 +332,7 @@ Editor.prototype = {
|
|||
this._prefObserver.on(AUTO_CLOSE, this.reloadPreferences);
|
||||
this._prefObserver.on(AUTOCOMPLETE, this.reloadPreferences);
|
||||
this._prefObserver.on(DETECT_INDENT, this.reloadPreferences);
|
||||
this._prefObserver.on(ENABLE_CODE_FOLDING, this.reloadPreferences);
|
||||
|
||||
this.reloadPreferences();
|
||||
def.resolve();
|
||||
|
@ -430,6 +430,7 @@ Editor.prototype = {
|
|||
this.setOption("keyMap", keyMap)
|
||||
else
|
||||
this.setOption("keyMap", "default");
|
||||
this.updateCodeFoldingGutter();
|
||||
|
||||
this.resetIndentUnit();
|
||||
this.setupAutoCompletion();
|
||||
|
@ -955,6 +956,12 @@ Editor.prototype = {
|
|||
} else {
|
||||
cm.setOption(o, v);
|
||||
}
|
||||
|
||||
if (o === "enableCodeFolding") {
|
||||
// The new value maybe explicitly force foldGUtter on or off, ignoring
|
||||
// the prefs service.
|
||||
this.updateCodeFoldingGutter();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1036,10 +1043,46 @@ Editor.prototype = {
|
|||
this._prefObserver.off(AUTO_CLOSE, this.reloadPreferences);
|
||||
this._prefObserver.off(AUTOCOMPLETE, this.reloadPreferences);
|
||||
this._prefObserver.off(DETECT_INDENT, this.reloadPreferences);
|
||||
this._prefObserver.off(ENABLE_CODE_FOLDING, this.reloadPreferences);
|
||||
this._prefObserver.destroy();
|
||||
}
|
||||
|
||||
this.emit("destroy");
|
||||
},
|
||||
|
||||
updateCodeFoldingGutter: function () {
|
||||
let shouldFoldGutter = this.config.enableCodeFolding,
|
||||
foldGutterIndex = this.config.gutters.indexOf("CodeMirror-foldgutter"),
|
||||
cm = editors.get(this);
|
||||
|
||||
if (shouldFoldGutter === undefined) {
|
||||
shouldFoldGutter = Services.prefs.getBoolPref(ENABLE_CODE_FOLDING);
|
||||
}
|
||||
|
||||
if (shouldFoldGutter) {
|
||||
// Add the gutter before enabling foldGutter
|
||||
if (foldGutterIndex === -1) {
|
||||
let gutters = this.config.gutters.slice();
|
||||
gutters.push("CodeMirror-foldgutter");
|
||||
this.setOption("gutters", gutters);
|
||||
}
|
||||
|
||||
this.setOption("foldGutter", true);
|
||||
} else {
|
||||
// No code should remain folded when folding is off.
|
||||
if (cm) {
|
||||
cm.execCommand("unfoldAll");
|
||||
}
|
||||
|
||||
// Remove the gutter so it doesn't take up space
|
||||
if (foldGutterIndex !== -1) {
|
||||
let gutters = this.config.gutters.slice();
|
||||
gutters.splice(foldGutterIndex, 1);
|
||||
this.setOption("gutters", gutters);
|
||||
}
|
||||
|
||||
this.setOption("foldGutter", false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
// Test to make sure that the editor reacts to preference changes
|
||||
|
||||
const TAB_SIZE = "devtools.editor.tabsize";
|
||||
const ENABLE_CODE_FOLDING = "devtools.editor.enableCodeFolding";
|
||||
const EXPAND_TAB = "devtools.editor.expandtab";
|
||||
const KEYMAP = "devtools.editor.keymap";
|
||||
const AUTO_CLOSE = "devtools.editor.autoclosebrackets";
|
||||
|
@ -17,6 +18,11 @@ function test() {
|
|||
waitForExplicitFinish();
|
||||
setup((ed, win) => {
|
||||
|
||||
Assert.deepEqual(ed.getOption("gutters"), [
|
||||
"CodeMirror-linenumbers",
|
||||
"breakpoints",
|
||||
"CodeMirror-foldgutter"], "gutters is correct");
|
||||
|
||||
ed.setText("Checking preferences.");
|
||||
|
||||
info ("Turning prefs off");
|
||||
|
@ -24,14 +30,21 @@ function test() {
|
|||
ed.setOption("autocomplete", true);
|
||||
|
||||
Services.prefs.setIntPref(TAB_SIZE, 2);
|
||||
Services.prefs.setBoolPref(ENABLE_CODE_FOLDING, false);
|
||||
Services.prefs.setBoolPref(EXPAND_TAB, false);
|
||||
Services.prefs.setCharPref(KEYMAP, "default");
|
||||
Services.prefs.setBoolPref(AUTO_CLOSE, false);
|
||||
Services.prefs.setBoolPref(AUTOCOMPLETE, false);
|
||||
Services.prefs.setBoolPref(DETECT_INDENT, false);
|
||||
|
||||
Assert.deepEqual(ed.getOption("gutters"), [
|
||||
"CodeMirror-linenumbers",
|
||||
"breakpoints"], "gutters is correct");
|
||||
|
||||
is(ed.getOption("tabSize"), 2, "tabSize is correct");
|
||||
is(ed.getOption("indentUnit"), 2, "indentUnit is correct");
|
||||
is(ed.getOption("foldGutter"), false, "foldGutter is correct");
|
||||
is(ed.getOption("enableCodeFolding"), undefined, "enableCodeFolding is correct");
|
||||
is(ed.getOption("indentWithTabs"), true, "indentWithTabs is correct");
|
||||
is(ed.getOption("keyMap"), "default", "keyMap is correct");
|
||||
is(ed.getOption("autoCloseBrackets"), "", "autoCloseBrackets is correct");
|
||||
|
@ -41,19 +54,46 @@ function test() {
|
|||
info ("Turning prefs on");
|
||||
|
||||
Services.prefs.setIntPref(TAB_SIZE, 4);
|
||||
Services.prefs.setBoolPref(ENABLE_CODE_FOLDING, true);
|
||||
Services.prefs.setBoolPref(EXPAND_TAB, true);
|
||||
Services.prefs.setCharPref(KEYMAP, "sublime");
|
||||
Services.prefs.setBoolPref(AUTO_CLOSE, true);
|
||||
Services.prefs.setBoolPref(AUTOCOMPLETE, true);
|
||||
|
||||
Assert.deepEqual(ed.getOption("gutters"), [
|
||||
"CodeMirror-linenumbers",
|
||||
"breakpoints",
|
||||
"CodeMirror-foldgutter"], "gutters is correct");
|
||||
|
||||
is(ed.getOption("tabSize"), 4, "tabSize is correct");
|
||||
is(ed.getOption("indentUnit"), 4, "indentUnit is correct");
|
||||
is(ed.getOption("foldGutter"), true, "foldGutter is correct");
|
||||
is(ed.getOption("enableCodeFolding"), undefined, "enableCodeFolding is correct");
|
||||
is(ed.getOption("indentWithTabs"), false, "indentWithTabs is correct");
|
||||
is(ed.getOption("keyMap"), "sublime", "keyMap is correct");
|
||||
is(ed.getOption("autoCloseBrackets"), "()[]{}''\"\"", "autoCloseBrackets is correct");
|
||||
is(ed.getOption("autocomplete"), true, "autocomplete is correct");
|
||||
ok(ed.isAutocompletionEnabled(), "Autocompletion is enabled");
|
||||
|
||||
info ("Forcing foldGutter off using enableCodeFolding");
|
||||
ed.setOption("enableCodeFolding", false);
|
||||
|
||||
is(ed.getOption("foldGutter"), false, "foldGutter is correct");
|
||||
is(ed.getOption("enableCodeFolding"), false, "enableCodeFolding is correct");
|
||||
Assert.deepEqual(ed.getOption("gutters"), [
|
||||
"CodeMirror-linenumbers",
|
||||
"breakpoints"], "gutters is correct");
|
||||
|
||||
info ("Forcing foldGutter on using enableCodeFolding");
|
||||
ed.setOption("enableCodeFolding", true);
|
||||
|
||||
is(ed.getOption("foldGutter"), true, "foldGutter is correct");
|
||||
is(ed.getOption("enableCodeFolding"), true, "enableCodeFolding is correct");
|
||||
Assert.deepEqual(ed.getOption("gutters"), [
|
||||
"CodeMirror-linenumbers",
|
||||
"breakpoints",
|
||||
"CodeMirror-foldgutter"], "gutters is correct");
|
||||
|
||||
info ("Checking indentation detection");
|
||||
|
||||
Services.prefs.setBoolPref(DETECT_INDENT, true);
|
||||
|
|
|
@ -35,14 +35,14 @@ let test = asyncTest(function*() {
|
|||
let onHighlighted = editor.once("node-highlighted");
|
||||
|
||||
info("Simulate a mousemove event on the div selector");
|
||||
editor._onMouseMove({clientX: 40, clientY: 10});
|
||||
editor._onMouseMove({clientX: 56, clientY: 10});
|
||||
yield onHighlighted;
|
||||
|
||||
ok(editor.highlighter.isShown, "The highlighter is now shown");
|
||||
is(editor.highlighter.options.selector, "div", "The selector is correct");
|
||||
|
||||
info("Simulate a mousemove event elsewhere in the editor");
|
||||
editor._onMouseMove({clientX: 0, clientY: 0});
|
||||
editor._onMouseMove({clientX: 16, clientY: 0});
|
||||
|
||||
ok(!editor.highlighter.isShown, "The highlighter is now hidden");
|
||||
});
|
||||
|
|
|
@ -496,7 +496,7 @@ let UI = {
|
|||
|
||||
Task.spawn(function() {
|
||||
if (project.type == "runtimeApp") {
|
||||
yield UI.busyUntil(AppManager.runRuntimeApp(), "running app");
|
||||
yield UI.busyUntil(AppManager.launchRuntimeApp(), "running app");
|
||||
}
|
||||
yield UI.createToolbox();
|
||||
});
|
||||
|
@ -1014,7 +1014,7 @@ let Cmds = {
|
|||
case "hosted":
|
||||
return UI.busyUntil(AppManager.installAndRunProject(), "installing and running app");
|
||||
case "runtimeApp":
|
||||
return UI.busyUntil(AppManager.runRuntimeApp(), "running app");
|
||||
return UI.busyUntil(AppManager.launchOrReloadRuntimeApp(), "launching / reloading app");
|
||||
case "tab":
|
||||
return UI.busyUntil(AppManager.reloadTab(), "reloading tab");
|
||||
}
|
||||
|
|
|
@ -326,7 +326,9 @@ exports.AppManager = AppManager = {
|
|||
|
||||
_selectedProject: null,
|
||||
set selectedProject(value) {
|
||||
if (value != this.selectedProject) {
|
||||
// A regular comparison still sees a difference when equal in some cases
|
||||
if (JSON.stringify(this._selectedProject) !==
|
||||
JSON.stringify(value)) {
|
||||
this._selectedProject = value;
|
||||
|
||||
// Clear out tab store's selected state, if any
|
||||
|
@ -439,9 +441,19 @@ exports.AppManager = AppManager = {
|
|||
return deferred.promise;
|
||||
},
|
||||
|
||||
runRuntimeApp: function() {
|
||||
launchRuntimeApp: function() {
|
||||
if (this.selectedProject && this.selectedProject.type != "runtimeApp") {
|
||||
return promise.reject("attempting to run a non-runtime app");
|
||||
return promise.reject("attempting to launch a non-runtime app");
|
||||
}
|
||||
let client = this.connection.client;
|
||||
let actor = this._listTabsResponse.webappsActor;
|
||||
let manifest = this.getProjectManifestURL(this.selectedProject);
|
||||
return AppActorFront.launchApp(client, actor, manifest);
|
||||
},
|
||||
|
||||
launchOrReloadRuntimeApp: function() {
|
||||
if (this.selectedProject && this.selectedProject.type != "runtimeApp") {
|
||||
return promise.reject("attempting to launch / reload a non-runtime app");
|
||||
}
|
||||
let client = this.connection.client;
|
||||
let actor = this._listTabsResponse.webappsActor;
|
||||
|
|
|
@ -303,7 +303,7 @@ class Automation(object):
|
|||
permDB = sqlite3.connect(os.path.join(profileDir, "permissions.sqlite"))
|
||||
cursor = permDB.cursor();
|
||||
|
||||
cursor.execute("PRAGMA user_version=3");
|
||||
cursor.execute("PRAGMA user_version=4");
|
||||
|
||||
# SQL copied from nsPermissionManager.cpp
|
||||
cursor.execute("""CREATE TABLE IF NOT EXISTS moz_hosts (
|
||||
|
@ -313,13 +313,14 @@ class Automation(object):
|
|||
permission INTEGER,
|
||||
expireType INTEGER,
|
||||
expireTime INTEGER,
|
||||
modificationTime INTEGER,
|
||||
appId INTEGER,
|
||||
isInBrowserElement INTEGER)""")
|
||||
|
||||
# Insert desired permissions
|
||||
for perm in permissions.keys():
|
||||
for host,allow in permissions[perm]:
|
||||
cursor.execute("INSERT INTO moz_hosts values(NULL, ?, ?, ?, 0, 0, 0, 0)",
|
||||
cursor.execute("INSERT INTO moz_hosts values(NULL, ?, ?, ?, 0, 0, 0, 0, 0)",
|
||||
(host, perm, 1 if allow else 2))
|
||||
|
||||
# Commit and close
|
||||
|
|
|
@ -1714,12 +1714,16 @@ ContentChild::RecvAddPermission(const IPC::Permission& permission)
|
|||
getter_AddRefs(principal));
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
|
||||
// child processes don't care about modification time.
|
||||
int64_t modificationTime = 0;
|
||||
|
||||
permissionManager->AddInternal(principal,
|
||||
nsCString(permission.type),
|
||||
permission.capability,
|
||||
0,
|
||||
permission.expireType,
|
||||
permission.expireTime,
|
||||
modificationTime,
|
||||
nsPermissionManager::eNotify,
|
||||
nsPermissionManager::eNoDBOperation);
|
||||
#endif
|
||||
|
|
|
@ -357,7 +357,7 @@ nsPermissionManager::AppClearDataObserverInit()
|
|||
// nsPermissionManager Implementation
|
||||
|
||||
static const char kPermissionsFileName[] = "permissions.sqlite";
|
||||
#define HOSTS_SCHEMA_VERSION 3
|
||||
#define HOSTS_SCHEMA_VERSION 4
|
||||
|
||||
static const char kHostpermFileName[] = "hostperm.1";
|
||||
|
||||
|
@ -432,8 +432,12 @@ nsPermissionManager::Init()
|
|||
rv = GetPrincipal(perm.host, perm.appId, perm.isInBrowserElement, getter_AddRefs(principal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// The child process doesn't care about modification times - it neither
|
||||
// reads nor writes, nor removes them based on the date - so 0 (which
|
||||
// will end up as now()) is fine.
|
||||
uint64_t modificationTime = 0;
|
||||
AddInternal(principal, perm.type, perm.capability, 0, perm.expireType,
|
||||
perm.expireTime, eNotify, eNoDBOperation);
|
||||
perm.expireTime, modificationTime, eNotify, eNoDBOperation);
|
||||
}
|
||||
|
||||
// Stop here; we don't need the DB in the child process
|
||||
|
@ -546,6 +550,23 @@ nsPermissionManager::InitDB(bool aRemoveFile)
|
|||
|
||||
// fall through to the next upgrade
|
||||
|
||||
// Version 3->4 is the creation of the modificationTime field.
|
||||
case 3:
|
||||
{
|
||||
rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"ALTER TABLE moz_hosts ADD modificationTime INTEGER"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// We leave the modificationTime at zero for all existing records; using
|
||||
// now() would mean, eg, that doing "remove all from the last hour"
|
||||
// within the first hour after migration would remove all permissions.
|
||||
|
||||
rv = mDBConn->SetSchemaVersion(HOSTS_SCHEMA_VERSION);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// fall through to the next upgrade
|
||||
|
||||
// current version.
|
||||
case HOSTS_SCHEMA_VERSION:
|
||||
break;
|
||||
|
@ -561,7 +582,7 @@ nsPermissionManager::InitDB(bool aRemoveFile)
|
|||
// check if all the expected columns exist
|
||||
nsCOMPtr<mozIStorageStatement> stmt;
|
||||
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"SELECT host, type, permission, expireType, expireTime, appId, isInBrowserElement FROM moz_hosts"),
|
||||
"SELECT host, type, permission, expireType, expireTime, modificationTime, appId, isInBrowserElement FROM moz_hosts"),
|
||||
getter_AddRefs(stmt));
|
||||
if (NS_SUCCEEDED(rv))
|
||||
break;
|
||||
|
@ -583,8 +604,8 @@ nsPermissionManager::InitDB(bool aRemoveFile)
|
|||
// cache frequently used statements (for insertion, deletion, and updating)
|
||||
rv = mDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
|
||||
"INSERT INTO moz_hosts "
|
||||
"(id, host, type, permission, expireType, expireTime, appId, isInBrowserElement) "
|
||||
"VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)"), getter_AddRefs(mStmtInsert));
|
||||
"(id, host, type, permission, expireType, expireTime, modificationTime, appId, isInBrowserElement) "
|
||||
"VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)"), getter_AddRefs(mStmtInsert));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
|
||||
|
@ -594,7 +615,7 @@ nsPermissionManager::InitDB(bool aRemoveFile)
|
|||
|
||||
rv = mDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
|
||||
"UPDATE moz_hosts "
|
||||
"SET permission = ?2, expireType= ?3, expireTime = ?4 WHERE id = ?1"),
|
||||
"SET permission = ?2, expireType= ?3, expireTime = ?4, modificationTime = ?5 WHERE id = ?1"),
|
||||
getter_AddRefs(mStmtUpdate));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -626,6 +647,7 @@ nsPermissionManager::CreateTable()
|
|||
",permission INTEGER"
|
||||
",expireType INTEGER"
|
||||
",expireTime INTEGER"
|
||||
",modificationTime INTEGER"
|
||||
",appId INTEGER"
|
||||
",isInBrowserElement INTEGER"
|
||||
")"));
|
||||
|
@ -679,8 +701,11 @@ nsPermissionManager::AddFromPrincipal(nsIPrincipal* aPrincipal,
|
|||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// A modificationTime of zero will cause AddInternal to use now().
|
||||
int64_t modificationTime = 0;
|
||||
|
||||
return AddInternal(aPrincipal, nsDependentCString(aType), aPermission, 0,
|
||||
aExpireType, aExpireTime, eNotify, eWriteToDB);
|
||||
aExpireType, aExpireTime, modificationTime, eNotify, eWriteToDB);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -690,6 +715,7 @@ nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal,
|
|||
int64_t aID,
|
||||
uint32_t aExpireType,
|
||||
int64_t aExpireTime,
|
||||
int64_t aModificationTime,
|
||||
NotifyOperationType aNotifyOperation,
|
||||
DBOperationType aDBOperation)
|
||||
{
|
||||
|
@ -760,15 +786,27 @@ nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal,
|
|||
// even if the new permission is UNKNOWN_ACTION (which means a "logical
|
||||
// remove" of the default)
|
||||
op = eOperationReplacingDefault;
|
||||
else if (aID == cIDPermissionIsDefault)
|
||||
// We are adding a default permission but a "real" permission already
|
||||
// exists. This almost-certainly means we just did a removeAllSince and
|
||||
// are re-importing defaults - so we can ignore this.
|
||||
op = eOperationNone;
|
||||
else if (aPermission == nsIPermissionManager::UNKNOWN_ACTION)
|
||||
op = eOperationRemoving;
|
||||
else
|
||||
op = eOperationChanging;
|
||||
}
|
||||
|
||||
// child processes should *always* be passed a modificationTime of zero.
|
||||
MOZ_ASSERT(!IsChildProcess() || aModificationTime == 0);
|
||||
|
||||
// do the work for adding, deleting, or changing a permission:
|
||||
// update the in-memory list, write to the db, and notify consumers.
|
||||
int64_t id;
|
||||
if (aModificationTime == 0) {
|
||||
aModificationTime = PR_Now() / 1000;
|
||||
}
|
||||
|
||||
switch (op) {
|
||||
case eOperationNone:
|
||||
{
|
||||
|
@ -786,7 +824,9 @@ nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal,
|
|||
id = aID;
|
||||
}
|
||||
|
||||
entry->GetPermissions().AppendElement(PermissionEntry(id, typeIndex, aPermission, aExpireType, aExpireTime));
|
||||
entry->GetPermissions().AppendElement(PermissionEntry(id, typeIndex, aPermission,
|
||||
aExpireType, aExpireTime,
|
||||
aModificationTime));
|
||||
|
||||
if (aDBOperation == eWriteToDB && aExpireType != nsIPermissionManager::EXPIRE_SESSION) {
|
||||
uint32_t appId;
|
||||
|
@ -797,7 +837,7 @@ nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal,
|
|||
rv = aPrincipal->GetIsInBrowserElement(&isInBrowserElement);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
UpdateDB(op, mStmtInsert, id, host, aType, aPermission, aExpireType, aExpireTime, appId, isInBrowserElement);
|
||||
UpdateDB(op, mStmtInsert, id, host, aType, aPermission, aExpireType, aExpireTime, aModificationTime, appId, isInBrowserElement);
|
||||
}
|
||||
|
||||
if (aNotifyOperation == eNotify) {
|
||||
|
@ -824,7 +864,7 @@ nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal,
|
|||
// We care only about the id here so we pass dummy values for all other
|
||||
// parameters.
|
||||
UpdateDB(op, mStmtDelete, id, EmptyCString(), EmptyCString(), 0,
|
||||
nsIPermissionManager::EXPIRE_NEVER, 0, 0, false);
|
||||
nsIPermissionManager::EXPIRE_NEVER, 0, 0, 0, false);
|
||||
|
||||
if (aNotifyOperation == eNotify) {
|
||||
NotifyObserversWithPermission(host,
|
||||
|
@ -866,12 +906,13 @@ nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal,
|
|||
entry->GetPermissions()[index].mPermission = aPermission;
|
||||
entry->GetPermissions()[index].mExpireType = aExpireType;
|
||||
entry->GetPermissions()[index].mExpireTime = aExpireTime;
|
||||
entry->GetPermissions()[index].mModificationTime = aModificationTime;
|
||||
|
||||
if (aDBOperation == eWriteToDB && aExpireType != nsIPermissionManager::EXPIRE_SESSION)
|
||||
// We care only about the id, the permission and expireType/expireTime here.
|
||||
// We care only about the id, the permission and expireType/expireTime/modificationTime here.
|
||||
// We pass dummy values for all other parameters.
|
||||
UpdateDB(op, mStmtUpdate, id, EmptyCString(), EmptyCString(),
|
||||
aPermission, aExpireType, aExpireTime, 0, false);
|
||||
aPermission, aExpireType, aExpireTime, aModificationTime, 0, false);
|
||||
|
||||
if (aNotifyOperation == eNotify) {
|
||||
NotifyObserversWithPermission(host,
|
||||
|
@ -915,6 +956,7 @@ nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal,
|
|||
entry->GetPermissions()[index].mPermission = aPermission;
|
||||
entry->GetPermissions()[index].mExpireType = aExpireType;
|
||||
entry->GetPermissions()[index].mExpireTime = aExpireTime;
|
||||
entry->GetPermissions()[index].mModificationTime = aModificationTime;
|
||||
|
||||
// If requested, create the entry in the DB.
|
||||
if (aDBOperation == eWriteToDB) {
|
||||
|
@ -926,7 +968,8 @@ nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal,
|
|||
rv = aPrincipal->GetIsInBrowserElement(&isInBrowserElement);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
UpdateDB(eOperationAdding, mStmtInsert, id, host, aType, aPermission, aExpireType, aExpireTime, appId, isInBrowserElement);
|
||||
UpdateDB(eOperationAdding, mStmtInsert, id, host, aType, aPermission,
|
||||
aExpireType, aExpireTime, aModificationTime, appId, isInBrowserElement);
|
||||
}
|
||||
|
||||
if (aNotifyOperation == eNotify) {
|
||||
|
@ -983,6 +1026,7 @@ nsPermissionManager::RemoveFromPrincipal(nsIPrincipal* aPrincipal,
|
|||
0,
|
||||
nsIPermissionManager::EXPIRE_NEVER,
|
||||
0,
|
||||
0,
|
||||
eNotify,
|
||||
eWriteToDB);
|
||||
}
|
||||
|
@ -994,6 +1038,13 @@ nsPermissionManager::RemoveAll()
|
|||
return RemoveAllInternal(true);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPermissionManager::RemoveAllSince(int64_t aSince)
|
||||
{
|
||||
ENSURE_NOT_CHILD_PROCESS;
|
||||
return RemoveAllModifiedSince(aSince);
|
||||
}
|
||||
|
||||
void
|
||||
nsPermissionManager::CloseDB(bool aRebuildOnSuccess)
|
||||
{
|
||||
|
@ -1323,12 +1374,16 @@ nsPermissionManager::GetPermissionHashKey(const nsACString& aHost,
|
|||
// helper struct for passing arguments into hash enumeration callback.
|
||||
struct nsGetEnumeratorData
|
||||
{
|
||||
nsGetEnumeratorData(nsCOMArray<nsIPermission> *aArray, const nsTArray<nsCString> *aTypes)
|
||||
nsGetEnumeratorData(nsCOMArray<nsIPermission> *aArray,
|
||||
const nsTArray<nsCString> *aTypes,
|
||||
int64_t aSince = 0)
|
||||
: array(aArray)
|
||||
, types(aTypes) {}
|
||||
, types(aTypes)
|
||||
, since(aSince) {}
|
||||
|
||||
nsCOMArray<nsIPermission> *array;
|
||||
const nsTArray<nsCString> *types;
|
||||
int64_t since;
|
||||
};
|
||||
|
||||
static PLDHashOperator
|
||||
|
@ -1395,6 +1450,76 @@ NS_IMETHODIMP nsPermissionManager::Observe(nsISupports *aSubject, const char *aT
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
AddPermissionsModifiedSinceToList(
|
||||
nsPermissionManager::PermissionHashKey* entry, void* arg)
|
||||
{
|
||||
nsGetEnumeratorData* data = static_cast<nsGetEnumeratorData *>(arg);
|
||||
|
||||
for (size_t i = 0; i < entry->GetPermissions().Length(); ++i) {
|
||||
const nsPermissionManager::PermissionEntry& permEntry = entry->GetPermissions()[i];
|
||||
|
||||
if (data->since > permEntry.mModificationTime) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsPermission* perm = new nsPermission(entry->GetKey()->mHost,
|
||||
entry->GetKey()->mAppId,
|
||||
entry->GetKey()->mIsInBrowserElement,
|
||||
data->types->ElementAt(permEntry.mType),
|
||||
permEntry.mPermission,
|
||||
permEntry.mExpireType,
|
||||
permEntry.mExpireTime);
|
||||
|
||||
data->array->AppendObject(perm);
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsPermissionManager::RemoveAllModifiedSince(int64_t aModificationTime)
|
||||
{
|
||||
ENSURE_NOT_CHILD_PROCESS;
|
||||
|
||||
// roll an nsCOMArray of all our permissions, then hand out an enumerator
|
||||
nsCOMArray<nsIPermission> array;
|
||||
nsGetEnumeratorData data(&array, &mTypeArray, aModificationTime);
|
||||
|
||||
mPermissionTable.EnumerateEntries(AddPermissionsModifiedSinceToList, &data);
|
||||
|
||||
for (int32_t i = 0; i<array.Count(); ++i) {
|
||||
nsAutoCString host;
|
||||
bool isInBrowserElement = false;
|
||||
nsAutoCString type;
|
||||
uint32_t appId = 0;
|
||||
|
||||
array[i]->GetHost(host);
|
||||
array[i]->GetIsInBrowserElement(&isInBrowserElement);
|
||||
array[i]->GetType(type);
|
||||
array[i]->GetAppId(&appId);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
if (NS_FAILED(GetPrincipal(host, appId, isInBrowserElement,
|
||||
getter_AddRefs(principal)))) {
|
||||
NS_ERROR("GetPrincipal() failed!");
|
||||
continue;
|
||||
}
|
||||
// AddInternal handles removal, so let it do the work...
|
||||
AddInternal(
|
||||
principal,
|
||||
type,
|
||||
nsIPermissionManager::UNKNOWN_ACTION,
|
||||
0,
|
||||
nsIPermissionManager::EXPIRE_NEVER, 0, 0,
|
||||
nsPermissionManager::eNotify,
|
||||
nsPermissionManager::eWriteToDB);
|
||||
}
|
||||
// now re-import any defaults as they may now be required if we just deleted
|
||||
// an override.
|
||||
ImportDefaults();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
nsPermissionManager::GetPermissionsForApp(nsPermissionManager::PermissionHashKey* entry, void* arg)
|
||||
{
|
||||
|
@ -1475,6 +1600,7 @@ nsPermissionManager::RemovePermissionsForApp(uint32_t aAppId, bool aBrowserOnly)
|
|||
0,
|
||||
nsIPermissionManager::EXPIRE_NEVER,
|
||||
0,
|
||||
0,
|
||||
nsPermissionManager::eNotify,
|
||||
nsPermissionManager::eNoDBOperation);
|
||||
}
|
||||
|
@ -1646,7 +1772,7 @@ nsPermissionManager::Read()
|
|||
|
||||
nsCOMPtr<mozIStorageStatement> stmt;
|
||||
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"SELECT id, host, type, permission, expireType, expireTime, appId, isInBrowserElement "
|
||||
"SELECT id, host, type, permission, expireType, expireTime, modificationTime, appId, isInBrowserElement "
|
||||
"FROM moz_hosts"), getter_AddRefs(stmt));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -1655,6 +1781,7 @@ nsPermissionManager::Read()
|
|||
uint32_t permission;
|
||||
uint32_t expireType;
|
||||
int64_t expireTime;
|
||||
int64_t modificationTime;
|
||||
uint32_t appId;
|
||||
bool isInBrowserElement;
|
||||
bool hasResult;
|
||||
|
@ -1682,15 +1809,17 @@ nsPermissionManager::Read()
|
|||
permission = stmt->AsInt32(3);
|
||||
expireType = stmt->AsInt32(4);
|
||||
|
||||
// convert into int64_t value (milliseconds)
|
||||
// convert into int64_t values (milliseconds)
|
||||
expireTime = stmt->AsInt64(5);
|
||||
modificationTime = stmt->AsInt64(6);
|
||||
|
||||
if (stmt->AsInt64(6) < 0) {
|
||||
if (stmt->AsInt64(7) < 0) {
|
||||
readError = true;
|
||||
continue;
|
||||
}
|
||||
appId = static_cast<uint32_t>(stmt->AsInt64(6));
|
||||
isInBrowserElement = static_cast<bool>(stmt->AsInt32(7));
|
||||
|
||||
appId = static_cast<uint32_t>(stmt->AsInt64(7));
|
||||
isInBrowserElement = static_cast<bool>(stmt->AsInt32(8));
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
nsresult rv = GetPrincipal(host, appId, isInBrowserElement, getter_AddRefs(principal));
|
||||
|
@ -1700,7 +1829,7 @@ nsPermissionManager::Read()
|
|||
}
|
||||
|
||||
rv = AddInternal(principal, type, permission, id, expireType, expireTime,
|
||||
eDontNotify, eNoDBOperation);
|
||||
modificationTime, eDontNotify, eNoDBOperation);
|
||||
if (NS_FAILED(rv)) {
|
||||
readError = true;
|
||||
continue;
|
||||
|
@ -1848,8 +1977,14 @@ nsPermissionManager::_DoImport(nsIInputStream *inputStream, mozIStorageConnectio
|
|||
nsresult rv = GetPrincipal(lineArray[3], getter_AddRefs(principal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// the import file format doesn't handle modification times, so we use
|
||||
// 0, which AddInternal will convert to now()
|
||||
int64_t modificationTime = 0;
|
||||
|
||||
rv = AddInternal(principal, lineArray[1], permission, id,
|
||||
nsIPermissionManager::EXPIRE_NEVER, 0, eDontNotify, operation);
|
||||
nsIPermissionManager::EXPIRE_NEVER, 0,
|
||||
modificationTime,
|
||||
eDontNotify, operation);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
|
@ -1880,6 +2015,7 @@ nsPermissionManager::UpdateDB(OperationType aOp,
|
|||
uint32_t aPermission,
|
||||
uint32_t aExpireType,
|
||||
int64_t aExpireTime,
|
||||
int64_t aModificationTime,
|
||||
uint32_t aAppId,
|
||||
bool aIsInBrowserElement)
|
||||
{
|
||||
|
@ -1912,10 +2048,13 @@ nsPermissionManager::UpdateDB(OperationType aOp,
|
|||
rv = aStmt->BindInt64ByIndex(5, aExpireTime);
|
||||
if (NS_FAILED(rv)) break;
|
||||
|
||||
rv = aStmt->BindInt64ByIndex(6, aAppId);
|
||||
rv = aStmt->BindInt64ByIndex(6, aModificationTime);
|
||||
if (NS_FAILED(rv)) break;
|
||||
|
||||
rv = aStmt->BindInt64ByIndex(7, aIsInBrowserElement);
|
||||
rv = aStmt->BindInt64ByIndex(7, aAppId);
|
||||
if (NS_FAILED(rv)) break;
|
||||
|
||||
rv = aStmt->BindInt64ByIndex(8, aIsInBrowserElement);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1937,6 +2076,9 @@ nsPermissionManager::UpdateDB(OperationType aOp,
|
|||
if (NS_FAILED(rv)) break;
|
||||
|
||||
rv = aStmt->BindInt64ByIndex(3, aExpireTime);
|
||||
if (NS_FAILED(rv)) break;
|
||||
|
||||
rv = aStmt->BindInt64ByIndex(4, aModificationTime);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,12 +37,14 @@ public:
|
|||
{
|
||||
public:
|
||||
PermissionEntry(int64_t aID, uint32_t aType, uint32_t aPermission,
|
||||
uint32_t aExpireType, int64_t aExpireTime)
|
||||
uint32_t aExpireType, int64_t aExpireTime,
|
||||
int64_t aModificationTime)
|
||||
: mID(aID)
|
||||
, mType(aType)
|
||||
, mPermission(aPermission)
|
||||
, mExpireType(aExpireType)
|
||||
, mExpireTime(aExpireTime)
|
||||
, mModificationTime(aModificationTime)
|
||||
, mNonSessionPermission(aPermission)
|
||||
, mNonSessionExpireType(aExpireType)
|
||||
, mNonSessionExpireTime(aExpireTime)
|
||||
|
@ -53,6 +55,7 @@ public:
|
|||
uint32_t mPermission;
|
||||
uint32_t mExpireType;
|
||||
int64_t mExpireTime;
|
||||
int64_t mModificationTime;
|
||||
uint32_t mNonSessionPermission;
|
||||
uint32_t mNonSessionExpireType;
|
||||
uint32_t mNonSessionExpireTime;
|
||||
|
@ -154,7 +157,7 @@ public:
|
|||
|
||||
// unknown permission... return relevant data
|
||||
return PermissionEntry(-1, aType, nsIPermissionManager::UNKNOWN_ACTION,
|
||||
nsIPermissionManager::EXPIRE_NEVER, 0);
|
||||
nsIPermissionManager::EXPIRE_NEVER, 0, 0);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -200,6 +203,7 @@ public:
|
|||
int64_t aID,
|
||||
uint32_t aExpireType,
|
||||
int64_t aExpireTime,
|
||||
int64_t aModificationTime,
|
||||
NotifyOperationType aNotifyOperation,
|
||||
DBOperationType aDBOperation);
|
||||
|
||||
|
@ -260,6 +264,7 @@ private:
|
|||
uint32_t aPermission,
|
||||
uint32_t aExpireType,
|
||||
int64_t aExpireTime,
|
||||
int64_t aModificationTime,
|
||||
uint32_t aAppId,
|
||||
bool aIsInBrowserElement);
|
||||
|
||||
|
@ -299,6 +304,13 @@ private:
|
|||
RemoveExpiredPermissionsForAppEnumerator(PermissionHashKey* entry,
|
||||
void* nonused);
|
||||
|
||||
|
||||
/**
|
||||
* This method removes all permissions modified after the specified time.
|
||||
*/
|
||||
nsresult
|
||||
RemoveAllModifiedSince(int64_t aModificationTime);
|
||||
|
||||
nsCOMPtr<nsIObserverService> mObserverService;
|
||||
nsCOMPtr<nsIIDNService> mIDNService;
|
||||
|
||||
|
|
|
@ -3,8 +3,15 @@
|
|||
|
||||
// The origin we use in most of the tests.
|
||||
const TEST_ORIGIN = "example.org";
|
||||
const TEST_ORIGIN_2 = "example.com";
|
||||
const TEST_PERMISSION = "test-permission";
|
||||
|
||||
function promiseTimeout(delay) {
|
||||
let deferred = Promise.defer();
|
||||
do_timeout(delay, deferred.resolve);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
@ -28,6 +35,7 @@ add_task(function* do_test() {
|
|||
conv.writeString("# this is a comment\n");
|
||||
conv.writeString("\n"); // a blank line!
|
||||
conv.writeString("host\t" + TEST_PERMISSION + "\t1\t" + TEST_ORIGIN + "\n");
|
||||
conv.writeString("host\t" + TEST_PERMISSION + "\t1\t" + TEST_ORIGIN_2 + "\n");
|
||||
ostream.close();
|
||||
|
||||
// Set the preference used by the permission manager so the file is read.
|
||||
|
@ -92,6 +100,47 @@ add_task(function* do_test() {
|
|||
do_check_eq(Ci.nsIPermissionManager.PROMPT_ACTION, findCapabilityViaEnum());
|
||||
yield checkCapabilityViaDB(Ci.nsIPermissionManager.PROMPT_ACTION);
|
||||
|
||||
// --------------------------------------------------------------
|
||||
// check default permissions and removeAllSince work as expected.
|
||||
pm.removeAll(); // ensure only defaults are there.
|
||||
|
||||
let permURI2 = NetUtil.newURI("http://" + TEST_ORIGIN_2);
|
||||
let principal2 = Services.scriptSecurityManager.getNoAppCodebasePrincipal(permURI2);
|
||||
|
||||
// default for both principals is allow.
|
||||
do_check_eq(Ci.nsIPermissionManager.ALLOW_ACTION,
|
||||
pm.testPermissionFromPrincipal(principal, TEST_PERMISSION));
|
||||
do_check_eq(Ci.nsIPermissionManager.ALLOW_ACTION,
|
||||
pm.testPermissionFromPrincipal(principal2, TEST_PERMISSION));
|
||||
|
||||
// Add a default override for TEST_ORIGIN_2 - this one should *not* be
|
||||
// restored in removeAllSince()
|
||||
pm.addFromPrincipal(principal2, TEST_PERMISSION, Ci.nsIPermissionManager.DENY_ACTION);
|
||||
do_check_eq(Ci.nsIPermissionManager.DENY_ACTION,
|
||||
pm.testPermissionFromPrincipal(principal2, TEST_PERMISSION));
|
||||
yield promiseTimeout(20);
|
||||
|
||||
let since = Number(Date.now());
|
||||
yield promiseTimeout(20);
|
||||
|
||||
// explicitly add a permission which overrides the default for the first
|
||||
// principal - this one *should* be removed by removeAllSince.
|
||||
pm.addFromPrincipal(principal, TEST_PERMISSION, Ci.nsIPermissionManager.DENY_ACTION);
|
||||
do_check_eq(Ci.nsIPermissionManager.DENY_ACTION,
|
||||
pm.testPermissionFromPrincipal(principal, TEST_PERMISSION));
|
||||
|
||||
// do a removeAllSince.
|
||||
pm.removeAllSince(since);
|
||||
|
||||
// the default for the first principal should re-appear as we modified it
|
||||
// later then |since|
|
||||
do_check_eq(Ci.nsIPermissionManager.ALLOW_ACTION,
|
||||
pm.testPermissionFromPrincipal(principal, TEST_PERMISSION));
|
||||
|
||||
// but the permission for principal2 should remain as we added that before |since|.
|
||||
do_check_eq(Ci.nsIPermissionManager.DENY_ACTION,
|
||||
pm.testPermissionFromPrincipal(principal2, TEST_PERMISSION));
|
||||
|
||||
// remove the temp file we created.
|
||||
file.remove(false);
|
||||
});
|
||||
|
|
|
@ -113,13 +113,25 @@ function run_test() {
|
|||
);
|
||||
}
|
||||
|
||||
let earliestNow = Number(Date.now());
|
||||
// Initialize the permission manager service
|
||||
var pm = Cc["@mozilla.org/permissionmanager;1"]
|
||||
.getService(Ci.nsIPermissionManager);
|
||||
let latestNow = Number(Date.now());
|
||||
|
||||
// The schema should still be 3. We want this test to be updated for each
|
||||
// schema update.
|
||||
do_check_eq(connection.schemaVersion, 3);
|
||||
// The schema should be upgraded to 4, and a 'modificationTime' column should
|
||||
// exist with all records having a value of 0.
|
||||
do_check_eq(connection.schemaVersion, 4);
|
||||
|
||||
let select = connection.createStatement("SELECT modificationTime FROM moz_hosts")
|
||||
let numMigrated = 0;
|
||||
while (select.executeStep()) {
|
||||
let thisModTime = select.getInt64(0);
|
||||
do_check_true(thisModTime == 0, "new modifiedTime field is correct");
|
||||
numMigrated += 1;
|
||||
}
|
||||
// check we found at least 1 record that was migrated.
|
||||
do_check_true(numMigrated > 0, "we found at least 1 record that was migrated");
|
||||
|
||||
// This permission should always be there.
|
||||
let principal = Cc["@mozilla.org/scriptsecuritymanager;1"]
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Test that removing permissions since a specified time behaves as expected.
|
||||
|
||||
let test_generator = do_run_test();
|
||||
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
test_generator.next();
|
||||
}
|
||||
|
||||
function continue_test()
|
||||
{
|
||||
do_run_generator(test_generator);
|
||||
}
|
||||
|
||||
function do_run_test() {
|
||||
// Set up a profile.
|
||||
let profile = do_get_profile();
|
||||
|
||||
let pm = Services.perms;
|
||||
|
||||
// to help with testing edge-cases, we will arrange for .removeAllSince to
|
||||
// remove *all* permissions from one principal and one permission from another.
|
||||
let permURI1 = NetUtil.newURI("http://example.com");
|
||||
let principal1 = Services.scriptSecurityManager.getNoAppCodebasePrincipal(permURI1);
|
||||
|
||||
let permURI2 = NetUtil.newURI("http://example.org");
|
||||
let principal2 = Services.scriptSecurityManager.getNoAppCodebasePrincipal(permURI2);
|
||||
|
||||
// add a permission now - this isn't going to be removed.
|
||||
pm.addFromPrincipal(principal1, "test/remove-since", 1);
|
||||
|
||||
// sleep briefly, then record the time - we'll remove all since then.
|
||||
do_timeout(20, continue_test);
|
||||
yield;
|
||||
|
||||
let since = Number(Date.now());
|
||||
|
||||
// *sob* - on Windows at least, the now recorded by nsPermissionManager.cpp
|
||||
// might be a couple of ms *earlier* than what JS sees. So another sleep
|
||||
// to ensure our |since| is greater than the time of the permissions we
|
||||
// are now adding. Sadly this means we'll never be able to test when since
|
||||
// exactly equals the modTime, but there you go...
|
||||
do_timeout(20, continue_test);
|
||||
yield;
|
||||
|
||||
// add another item - this second one should get nuked.
|
||||
pm.addFromPrincipal(principal1, "test/remove-since-2", 1);
|
||||
|
||||
// add 2 items for the second principal - both will be removed.
|
||||
pm.addFromPrincipal(principal2, "test/remove-since", 1);
|
||||
pm.addFromPrincipal(principal2, "test/remove-since-2", 1);
|
||||
|
||||
// do the removal.
|
||||
pm.removeAllSince(since);
|
||||
|
||||
// principal1 - the first one should remain.
|
||||
do_check_eq(1, pm.testPermissionFromPrincipal(principal1, "test/remove-since"));
|
||||
// but the second should have been removed.
|
||||
do_check_eq(0, pm.testPermissionFromPrincipal(principal1, "test/remove-since-2"));
|
||||
|
||||
// principal2 - both should have been removed.
|
||||
do_check_eq(0, pm.testPermissionFromPrincipal(principal2, "test/remove-since"));
|
||||
do_check_eq(0, pm.testPermissionFromPrincipal(principal2, "test/remove-since-2"));
|
||||
|
||||
do_finish_generator_test(test_generator);
|
||||
}
|
|
@ -23,6 +23,7 @@ support-files =
|
|||
[test_permmanager_getPermissionObject.js]
|
||||
[test_permmanager_notifications.js]
|
||||
[test_permmanager_removeall.js]
|
||||
[test_permmanager_removesince.js]
|
||||
[test_permmanager_load_invalid_entries.js]
|
||||
skip-if = debug == true
|
||||
[test_permmanager_idn.js]
|
||||
|
|
|
@ -84,8 +84,10 @@ CSS_KEY(-moz-isolate, _moz_isolate)
|
|||
CSS_KEY(-moz-isolate-override, _moz_isolate_override)
|
||||
CSS_KEY(-moz-left, _moz_left)
|
||||
CSS_KEY(-moz-list, _moz_list)
|
||||
CSS_KEY(-moz-mac-buttonactivetext, _moz_mac_buttonactivetext)
|
||||
CSS_KEY(-moz-mac-chrome-active, _moz_mac_chrome_active)
|
||||
CSS_KEY(-moz-mac-chrome-inactive, _moz_mac_chrome_inactive)
|
||||
CSS_KEY(-moz-mac-defaultbuttontext, _moz_mac_defaultbuttontext)
|
||||
CSS_KEY(-moz-mac-focusring, _moz_mac_focusring)
|
||||
CSS_KEY(-moz-mac-fullscreen-button, _moz_mac_fullscreen_button)
|
||||
CSS_KEY(-moz-mac-menuselect, _moz_mac_menuselect)
|
||||
|
|
|
@ -948,8 +948,10 @@ const KTableValue nsCSSProps::kColorKTable[] = {
|
|||
eCSSKeyword__moz_hyperlinktext, NS_COLOR_MOZ_HYPERLINKTEXT,
|
||||
eCSSKeyword__moz_html_cellhighlight, LookAndFeel::eColorID__moz_html_cellhighlight,
|
||||
eCSSKeyword__moz_html_cellhighlighttext, LookAndFeel::eColorID__moz_html_cellhighlighttext,
|
||||
eCSSKeyword__moz_mac_buttonactivetext, LookAndFeel::eColorID__moz_mac_buttonactivetext,
|
||||
eCSSKeyword__moz_mac_chrome_active, LookAndFeel::eColorID__moz_mac_chrome_active,
|
||||
eCSSKeyword__moz_mac_chrome_inactive, LookAndFeel::eColorID__moz_mac_chrome_inactive,
|
||||
eCSSKeyword__moz_mac_defaultbuttontext, LookAndFeel::eColorID__moz_mac_defaultbuttontext,
|
||||
eCSSKeyword__moz_mac_focusring, LookAndFeel::eColorID__moz_mac_focusring,
|
||||
eCSSKeyword__moz_mac_menuselect, LookAndFeel::eColorID__moz_mac_menuselect,
|
||||
eCSSKeyword__moz_mac_menushadow, LookAndFeel::eColorID__moz_mac_menushadow,
|
||||
|
|
|
@ -200,8 +200,11 @@ public class BrowserDB {
|
|||
return sDb.getFaviconForUrl(cr, faviconURL);
|
||||
}
|
||||
|
||||
public static String getFaviconUrlForHistoryUrl(ContentResolver cr, String url) {
|
||||
return sDb.getFaviconUrlForHistoryUrl(cr, url);
|
||||
/**
|
||||
* Try to find a usable favicon URL in the history or bookmarks table.
|
||||
*/
|
||||
public static String getFaviconURLFromPageURL(ContentResolver cr, String url) {
|
||||
return sDb.getFaviconURLFromPageURL(cr, url);
|
||||
}
|
||||
|
||||
public static void updateFaviconForUrl(ContentResolver cr, String pageUri, byte[] encodedFavicon, String faviconUri) {
|
||||
|
|
|
@ -58,6 +58,8 @@ public class LocalBrowserDB {
|
|||
// Calculate these once, at initialization. isLoggable is too expensive to
|
||||
// have in-line in each log call.
|
||||
private static final String LOGTAG = "GeckoLocalBrowserDB";
|
||||
private static final Integer FAVICON_ID_NOT_FOUND = Integer.MIN_VALUE;
|
||||
|
||||
private static final boolean logDebug = Log.isLoggable(LOGTAG, Log.DEBUG);
|
||||
protected static void debug(String message) {
|
||||
if (logDebug) {
|
||||
|
@ -998,19 +1000,38 @@ public class LocalBrowserDB {
|
|||
return FaviconDecoder.decodeFavicon(b);
|
||||
}
|
||||
|
||||
public String getFaviconUrlForHistoryUrl(ContentResolver cr, String uri) {
|
||||
final Cursor c = cr.query(mHistoryUriWithProfile,
|
||||
new String[] { History.FAVICON_URL },
|
||||
Combined.URL + " = ?",
|
||||
new String[] { uri },
|
||||
null);
|
||||
/**
|
||||
* Try to find a usable favicon URL in the history or bookmarks table.
|
||||
*/
|
||||
public String getFaviconURLFromPageURL(ContentResolver cr, String uri) {
|
||||
// Check first in the history table.
|
||||
Cursor c = cr.query(mHistoryUriWithProfile,
|
||||
new String[] { History.FAVICON_URL },
|
||||
Combined.URL + " = ?",
|
||||
new String[] { uri },
|
||||
null);
|
||||
|
||||
try {
|
||||
if (!c.moveToFirst()) {
|
||||
return null;
|
||||
if (c.moveToFirst()) {
|
||||
return c.getString(c.getColumnIndexOrThrow(History.FAVICON_URL));
|
||||
}
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
|
||||
// If that fails, check in the bookmarks table.
|
||||
c = cr.query(mBookmarksUriWithProfile,
|
||||
new String[] { Bookmarks.FAVICON_URL },
|
||||
Bookmarks.URL + " = ?",
|
||||
new String[] { uri },
|
||||
null);
|
||||
|
||||
try {
|
||||
if (c.moveToFirst()) {
|
||||
return c.getString(c.getColumnIndexOrThrow(Bookmarks.FAVICON_URL));
|
||||
}
|
||||
|
||||
return c.getString(c.getColumnIndexOrThrow(History.FAVICON_URL));
|
||||
return null;
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
|
@ -1027,10 +1048,66 @@ public class LocalBrowserDB {
|
|||
Uri faviconsUri = getAllFaviconsUri().buildUpon().
|
||||
appendQueryParameter(BrowserContract.PARAM_INSERT_IF_NEEDED, "true").build();
|
||||
|
||||
cr.update(faviconsUri,
|
||||
values,
|
||||
Favicons.URL + " = ?",
|
||||
new String[] { faviconUri });
|
||||
final int updated = cr.update(faviconsUri,
|
||||
values,
|
||||
Favicons.URL + " = ?",
|
||||
new String[] { faviconUri });
|
||||
|
||||
if (updated == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// After writing the encodedFavicon, ensure that the favicon_id in both the bookmark and
|
||||
// history tables are also up-to-date.
|
||||
final Integer id = getIDForFaviconURL(cr, faviconUri);
|
||||
if (id == FAVICON_ID_NOT_FOUND) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateHistoryAndBookmarksFaviconID(cr, pageUri, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates and returns the favicon ID of a target URL as an Integer.
|
||||
*/
|
||||
private Integer getIDForFaviconURL(ContentResolver cr, String faviconURL) {
|
||||
final Cursor c = cr.query(mFaviconsUriWithProfile,
|
||||
new String[] { Favicons._ID },
|
||||
Favicons.URL + " = ? AND " + Favicons.DATA + " IS NOT NULL",
|
||||
new String[] { faviconURL },
|
||||
null);
|
||||
|
||||
try {
|
||||
final int col = c.getColumnIndexOrThrow(Favicons._ID);
|
||||
if (c.moveToFirst() && !c.isNull(col)) {
|
||||
return c.getInt(col);
|
||||
}
|
||||
|
||||
// IDs can be negative, so we return a sentinel value indicating "not found".
|
||||
return FAVICON_ID_NOT_FOUND;
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the favicon ID in the history and bookmark tables after a new
|
||||
* favicon table entry is added.
|
||||
*/
|
||||
private void updateHistoryAndBookmarksFaviconID(ContentResolver cr, String pageURL, int id) {
|
||||
final ContentValues bookmarkValues = new ContentValues();
|
||||
bookmarkValues.put(Bookmarks.FAVICON_ID, id);
|
||||
cr.update(mBookmarksUriWithProfile,
|
||||
bookmarkValues,
|
||||
Bookmarks.URL + " = ?",
|
||||
new String[] { pageURL });
|
||||
|
||||
final ContentValues historyValues = new ContentValues();
|
||||
historyValues.put(History.FAVICON_ID, id);
|
||||
cr.update(mHistoryUriWithProfile,
|
||||
historyValues,
|
||||
History.URL + " = ?",
|
||||
new String[] { pageURL });
|
||||
}
|
||||
|
||||
public void updateThumbnailForUrl(ContentResolver cr, String uri,
|
||||
|
|
|
@ -17,6 +17,7 @@ import org.mozilla.gecko.util.GeckoJarReader;
|
|||
import org.mozilla.gecko.util.NonEvictingLruCache;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
|
@ -53,8 +54,6 @@ public class Favicons {
|
|||
|
||||
public static final int NOT_LOADING = 0;
|
||||
public static final int LOADED = 1;
|
||||
public static final int FLAG_PERSIST = 2;
|
||||
public static final int FLAG_SCALE = 4;
|
||||
|
||||
// The default Favicon to show if no other can be found.
|
||||
public static Bitmap defaultFavicon;
|
||||
|
@ -260,12 +259,15 @@ public class Favicons {
|
|||
}
|
||||
}
|
||||
|
||||
targetURL = BrowserDB.getFaviconUrlForHistoryUrl(context.getContentResolver(), pageURL);
|
||||
if (targetURL == null) {
|
||||
// Nothing in the history database. Fall back to the default URL and hope for the best.
|
||||
targetURL = guessDefaultFaviconURL(pageURL);
|
||||
// Try to find the faviconURL in the history and/or bookmarks table.
|
||||
final ContentResolver resolver = context.getContentResolver();
|
||||
targetURL = BrowserDB.getFaviconURLFromPageURL(resolver, pageURL);
|
||||
if (targetURL != null) {
|
||||
return targetURL;
|
||||
}
|
||||
return targetURL;
|
||||
|
||||
// If we still can't find it, fall back to the default URL and hope for the best.
|
||||
return guessDefaultFaviconURL(pageURL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -46,7 +46,6 @@ public class LoadFaviconTask {
|
|||
private static final HashMap<String, LoadFaviconTask> loadsInFlight = new HashMap<>();
|
||||
|
||||
public static final int FLAG_PERSIST = 1;
|
||||
public static final int FLAG_SCALE = 2;
|
||||
private static final int MAX_REDIRECTS_TO_FOLLOW = 5;
|
||||
// The default size of the buffer to use for downloading Favicons in the event no size is given
|
||||
// by the server.
|
||||
|
|
|
@ -37,7 +37,7 @@ interface nsIDOMWindow;
|
|||
interface nsIPermission;
|
||||
interface nsISimpleEnumerator;
|
||||
|
||||
[scriptable, uuid(c9fec678-f194-43c9-96b0-7bd9dbdd6bb0)]
|
||||
[scriptable, uuid(620d9b61-8997-4d13-aa64-ec03341dd75b)]
|
||||
interface nsIPermissionManager : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -132,6 +132,11 @@ interface nsIPermissionManager : nsISupports
|
|||
*/
|
||||
void removeAll();
|
||||
|
||||
/**
|
||||
* Clear all permission information added since the specified time.
|
||||
*/
|
||||
void removeAllSince(in int64_t since);
|
||||
|
||||
/**
|
||||
* Test whether a website has permission to perform the given action.
|
||||
* @param uri the uri to be tested
|
||||
|
|
|
@ -241,8 +241,12 @@ class Permissions(object):
|
|||
rows = cursor.execute("PRAGMA table_info(moz_hosts)")
|
||||
count = len(rows.fetchall())
|
||||
|
||||
# if the db contains 9 columns, we're using user_version 4
|
||||
if count == 9:
|
||||
statement = "INSERT INTO moz_hosts values(NULL, ?, ?, ?, 0, 0, 0, 0, 0)"
|
||||
cursor.execute("PRAGMA user_version=4;")
|
||||
# if the db contains 8 columns, we're using user_version 3
|
||||
if count == 8:
|
||||
elif count == 8:
|
||||
statement = "INSERT INTO moz_hosts values(NULL, ?, ?, ?, 0, 0, 0, 0)"
|
||||
cursor.execute("PRAGMA user_version=3;")
|
||||
else:
|
||||
|
|
|
@ -40,7 +40,18 @@ http://127.0.0.1:8888 privileged
|
|||
|
||||
cursor.execute("PRAGMA user_version=%d;" % version)
|
||||
|
||||
if version == 3:
|
||||
if version == 4:
|
||||
cursor.execute("""CREATE TABLE IF NOT EXISTS moz_hosts (
|
||||
id INTEGER PRIMARY KEY,
|
||||
host TEXT,
|
||||
type TEXT,
|
||||
permission INTEGER,
|
||||
expireType INTEGER,
|
||||
expireTime INTEGER,
|
||||
modificationTime INTEGER,
|
||||
appId INTEGER,
|
||||
isInBrowserElement INTEGER)""")
|
||||
elif version == 3:
|
||||
cursor.execute("""CREATE TABLE IF NOT EXISTS moz_hosts (
|
||||
id INTEGER PRIMARY KEY,
|
||||
host TEXT,
|
||||
|
@ -59,7 +70,7 @@ http://127.0.0.1:8888 privileged
|
|||
expireType INTEGER,
|
||||
expireTime INTEGER)""")
|
||||
else:
|
||||
raise Exception("version must be 2 or 3")
|
||||
raise Exception("version must be 2, 3 or 4")
|
||||
|
||||
permDB.commit()
|
||||
cursor.close()
|
||||
|
@ -149,7 +160,7 @@ http://127.0.0.1:8888 privileged
|
|||
|
||||
self.assertEqual(len(entries), 3)
|
||||
|
||||
columns = 8 if version == 3 else 6
|
||||
columns = 9 if version == 4 else (8 if version == 3 else 6)
|
||||
self.assertEqual(len(entries[0]), columns)
|
||||
for x in range(4, columns):
|
||||
self.assertEqual(entries[0][x], 0)
|
||||
|
@ -160,6 +171,8 @@ http://127.0.0.1:8888 privileged
|
|||
def test_existing_permissions_db_v3(self):
|
||||
self.verify_user_version(3)
|
||||
|
||||
def test_existing_permissions_db_v4(self):
|
||||
self.verify_user_version(4)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -14,6 +14,22 @@ button {
|
|||
text-shadow: none;
|
||||
}
|
||||
|
||||
button:hover:active {
|
||||
color: -moz-mac-buttonactivetext;
|
||||
}
|
||||
|
||||
/* When the window isn't focused, the default button background isn't drawn,
|
||||
* so don't change the text color then: */
|
||||
button[default="true"]:not(:-moz-window-inactive) {
|
||||
color: -moz-mac-defaultbuttontext;
|
||||
}
|
||||
|
||||
/* Likewise, when active (mousedown) but not hovering, the default button
|
||||
* background isn't drawn, override the previous selector for that case: */
|
||||
button[default="true"]:not(:hover):active {
|
||||
color: ButtonText;
|
||||
}
|
||||
|
||||
.button-text {
|
||||
margin: 1px 0 !important;
|
||||
-moz-margin-start: 3px !important;
|
||||
|
|
|
@ -126,10 +126,14 @@ public:
|
|||
|
||||
// colors needed by the Mac OS X theme
|
||||
|
||||
// foreground color of :hover:active buttons
|
||||
eColorID__moz_mac_buttonactivetext,
|
||||
// background color of chrome toolbars in active windows
|
||||
eColorID__moz_mac_chrome_active,
|
||||
// background color of chrome toolbars in inactive windows
|
||||
eColorID__moz_mac_chrome_inactive,
|
||||
// foreground color of default buttons
|
||||
eColorID__moz_mac_defaultbuttontext,
|
||||
//ring around text fields and lists
|
||||
eColorID__moz_mac_focusring,
|
||||
//colour used when mouse is over a menu item
|
||||
|
|
|
@ -137,6 +137,13 @@ nsLookAndFeel::NativeGetColor(ColorID aID, nscolor &aColor)
|
|||
// Thanks to mpt26@student.canterbury.ac.nz for the hardcoded values that form the defaults
|
||||
// if querying the Appearance Manager fails ;)
|
||||
//
|
||||
case eColorID__moz_mac_buttonactivetext:
|
||||
case eColorID__moz_mac_defaultbuttontext:
|
||||
if (nsCocoaFeatures::OnYosemiteOrLater()) {
|
||||
aColor = NS_RGB(0xFF,0xFF,0xFF);
|
||||
break;
|
||||
}
|
||||
// Otherwise fall through and return the regular button text:
|
||||
|
||||
case eColorID_buttontext:
|
||||
case eColorID__moz_buttonhovertext:
|
||||
|
|
|
@ -66,8 +66,10 @@ var colors = {
|
|||
"-moz-hyperlinktext": ["rgb(0, 0, 238)"],
|
||||
"-moz-html-cellhighlight": ["rgb(212, 212, 212)"],
|
||||
"-moz-html-cellhighlighttext": ["rgb(0, 0, 0)"],
|
||||
"-moz-mac-buttonactivetext": ["rgb(0, 0, 0)", "rgb(255, 255, 255)"],
|
||||
"-moz-mac-chrome-active": ["rgb(150, 150, 150)", "rgb(167, 167, 167)", "rgb(178, 178, 178)"],
|
||||
"-moz-mac-chrome-inactive": ["rgb(202, 202, 202)", "rgb(216, 216, 216)", "rgb(225, 225, 225)"],
|
||||
"-moz-mac-defaultbuttontext": ["rgb(0, 0, 0)", "rgb(255, 255, 255)"],
|
||||
//"-moz-mac-focusring": ["rgb(83, 144, 210)", "rgb(95, 112, 130)", "rgb(63, 152, 221)", "rgb(108, 126, 141)"],
|
||||
"-moz-mac-menuselect": ["rgb(115, 132, 153)", "rgb(127, 127, 127)", "rgb(56, 117, 215)", "rgb(255, 193, 31)", "rgb(243, 70, 72)", "rgb(255, 138, 34)", "rgb(102, 197, 71)", "rgb(140, 78, 184)"],
|
||||
"-moz-mac-menushadow": ["rgb(163, 163, 163)"],
|
||||
|
|
|
@ -215,8 +215,10 @@ const char nsXPLookAndFeel::sColorPrefs[][38] =
|
|||
"ui.-moz_menubarhovertext",
|
||||
"ui.-moz_eventreerow",
|
||||
"ui.-moz_oddtreerow",
|
||||
"ui.-moz-mac-buttonactivetext",
|
||||
"ui.-moz_mac_chrome_active",
|
||||
"ui.-moz_mac_chrome_inactive",
|
||||
"ui.-moz-mac-defaultbuttontext",
|
||||
"ui.-moz-mac-focusring",
|
||||
"ui.-moz-mac-menuselect",
|
||||
"ui.-moz-mac-menushadow",
|
||||
|
|
Загрузка…
Ссылка в новой задаче