зеркало из https://github.com/mozilla/gecko-dev.git
Bug 821630 - Fix retrieving blobs with get() in Settings API. r=gwagner
This commit is contained in:
Родитель
2c636e23fe
Коммит
807a748b11
|
@ -87,19 +87,9 @@ SettingsLock.prototype = {
|
|||
if (DEBUG) debug("MOZSETTINGS-SET-WARNING: " + key + " is not in the database.\n");
|
||||
}
|
||||
|
||||
let setReq;
|
||||
if (typeof(info.settings[key]) != 'object') {
|
||||
let obj = {settingName: key, defaultValue: defaultValue, userValue: userValue};
|
||||
if (DEBUG) debug("store1: " + JSON.stringify(obj));
|
||||
setReq = store.put(obj);
|
||||
} else {
|
||||
//Workaround for cloning issues
|
||||
let defaultVal = JSON.parse(JSON.stringify(defaultValue));
|
||||
let userVal = JSON.parse(JSON.stringify(userValue));
|
||||
let obj = {settingName: key, defaultValue: defaultVal, userValue: userVal};
|
||||
if (DEBUG) debug("store2: " + JSON.stringify(obj));
|
||||
setReq = store.put(obj);
|
||||
}
|
||||
let obj = {settingName: key, defaultValue: defaultValue, userValue: userValue};
|
||||
if (DEBUG) debug("store1: " + JSON.stringify(obj));
|
||||
let setReq = store.put(obj);
|
||||
|
||||
setReq.onsuccess = function() {
|
||||
lock._isBusy = false;
|
||||
|
@ -119,7 +109,7 @@ SettingsLock.prototype = {
|
|||
Services.DOMRequest.fireError(request, setReq.error.name)
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
checkKeyRequest.onerror = function(event) {
|
||||
if (!request.error) {
|
||||
Services.DOMRequest.fireError(request, checkKeyRequest.error.name)
|
||||
|
@ -133,7 +123,7 @@ SettingsLock.prototype = {
|
|||
|
||||
getReq.onsuccess = function(event) {
|
||||
if (DEBUG) debug("Request for '" + info.name + "' successful. " +
|
||||
"Record count: " + event.target.result.length);
|
||||
"Record count: " + event.target.result.length);
|
||||
|
||||
if (event.target.result.length == 0) {
|
||||
if (DEBUG) debug("MOZSETTINGS-GET-WARNING: " + info.name + " is not in the database.\n");
|
||||
|
@ -200,6 +190,31 @@ SettingsLock.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
_serializePreservingBinaries: function _serializePreservingBinaries(aObject) {
|
||||
// We need to serialize settings objects, otherwise they can change between
|
||||
// the set() call and the enqueued request being processed. We can't simply
|
||||
// parse(stringify(obj)) because that breaks things like Blobs, Files and
|
||||
// Dates, so we use stringify's replacer and parse's reviver parameters to
|
||||
// preserve binaries.
|
||||
let binaries = Object.create(null);
|
||||
let stringified = JSON.stringify(aObject, function(key, value) {
|
||||
let kind = ObjectWrapper.getObjectKind(value);
|
||||
if (kind == "file" || kind == "blob" || kind == "date") {
|
||||
let uuid = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator)
|
||||
.generateUUID().toString();
|
||||
binaries[uuid] = value;
|
||||
return uuid;
|
||||
}
|
||||
return value;
|
||||
});
|
||||
return JSON.parse(stringified, function(key, value) {
|
||||
if (value in binaries) {
|
||||
return binaries[value];
|
||||
}
|
||||
return value;
|
||||
});
|
||||
},
|
||||
|
||||
set: function set(aSettings) {
|
||||
if (!this._open) {
|
||||
dump("Settings lock not open!\n");
|
||||
|
@ -209,7 +224,7 @@ SettingsLock.prototype = {
|
|||
if (this._settingsManager.hasWritePrivileges) {
|
||||
let req = Services.DOMRequest.createRequest(this._settingsManager._window);
|
||||
if (DEBUG) debug("send: " + JSON.stringify(aSettings));
|
||||
let settings = JSON.parse(JSON.stringify(aSettings));
|
||||
let settings = this._serializePreservingBinaries(aSettings);
|
||||
this._requests.enqueue({request: req, intent: "set", settings: settings});
|
||||
this.createTransactionAndProcess();
|
||||
return req;
|
||||
|
@ -311,7 +326,6 @@ SettingsManager.prototype = {
|
|||
|
||||
switch (aMessage.name) {
|
||||
case "Settings:Change:Return:OK":
|
||||
if (DEBUG) debug("Settings:Change:Return:OK");
|
||||
if (this._onsettingchange || this._callbacks) {
|
||||
if (DEBUG) debug('data:' + msg.key + ':' + msg.value + '\n');
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ MOCHITEST_FILES = \
|
|||
test_settings_basics.html \
|
||||
test_settings_events.html \
|
||||
test_settings_onsettingchange.html \
|
||||
test_settings_blobs.html \
|
||||
$(NULL)
|
||||
|
||||
_CHROMEMOCHITEST_FILES = \
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=821630
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 821630 Settings API</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=821630">Mozilla Bug 821630</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript;version=1.8">
|
||||
|
||||
"use strict";
|
||||
|
||||
var comp = SpecialPowers.wrap(SpecialPowers.Components);
|
||||
comp.utils.import("resource://gre/modules/SettingsChangeNotifier.jsm");
|
||||
SpecialPowers.setBoolPref("dom.mozSettings.enabled", true);
|
||||
SpecialPowers.addPermission("settings-read", true, document);
|
||||
SpecialPowers.addPermission("settings-write", true, document);
|
||||
|
||||
function onUnwantedSuccess() {
|
||||
ok(false, "onUnwantedSuccess: shouldn't get here");
|
||||
}
|
||||
|
||||
function onFailure() {
|
||||
return function(s) {
|
||||
if (s) {
|
||||
ok(false, "in on Failure! - " + s);
|
||||
} else {
|
||||
ok(false, "in on Failure!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mozSettings = window.navigator.mozSettings;
|
||||
let req;
|
||||
|
||||
let storedBlob = new Blob([""], {"type": "text/xml"});
|
||||
|
||||
function checkBlob(blob) {
|
||||
try {
|
||||
let url = URL.createObjectURL(blob);
|
||||
ok(true, "Valid blob");
|
||||
} catch (e) {
|
||||
ok(false, "Valid blob");
|
||||
}
|
||||
}
|
||||
|
||||
let steps = [
|
||||
function() {
|
||||
let lock = mozSettings.createLock();
|
||||
req = lock.clear();
|
||||
req.onsuccess = next;
|
||||
req.onerror = onFailure("Deleting database");
|
||||
},
|
||||
function() {
|
||||
mozSettings.addObserver("test1", function(e) {
|
||||
checkBlob(e.settingValue);
|
||||
mozSettings.removeObserver("test1", this);
|
||||
next();
|
||||
});
|
||||
next();
|
||||
},
|
||||
function() {
|
||||
// next is called by the observer above
|
||||
let req = mozSettings.createLock().set({"test1": storedBlob});
|
||||
req.onerror = onFailure("Saving blob");
|
||||
},
|
||||
function() {
|
||||
let req = mozSettings.createLock().get("test1");
|
||||
req.onsuccess = function(event) {
|
||||
checkBlob(event.target.result["test1"]);
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure("Getting blob");
|
||||
},
|
||||
function() {
|
||||
let req = mozSettings.createLock().set({"test2": [1, 2, storedBlob, 4]});
|
||||
req.onsuccess = next;
|
||||
req.onerror = onFailure("Saving array");
|
||||
},
|
||||
function() {
|
||||
let req = mozSettings.createLock().get("test2");
|
||||
req.onsuccess = function(event) {
|
||||
let val = event.target.result["test2"];
|
||||
ok(Array.isArray(val), "Result is an array");
|
||||
ok(val[0] == 1 && val[1] == 2 && val[3] == 4, "Primitives are preserved");
|
||||
checkBlob(val[2]);
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure("Getting array");
|
||||
},
|
||||
function() {
|
||||
let req = mozSettings.createLock().set({"test3": {foo: "bar", baz: {number: 1, arr: [storedBlob]}}});
|
||||
req.onsuccess = next();
|
||||
req.onerror = onFailure("Saving object");
|
||||
},
|
||||
function() {
|
||||
let req = mozSettings.createLock().get("test3");
|
||||
req.onsuccess = function(event) {
|
||||
let val = event.target.result["test3"];
|
||||
ok(typeof(val) == "object", "Result is an object");
|
||||
ok("foo" in val && typeof(val.foo) == "string", "String property preserved");
|
||||
ok("baz" in val && typeof(val.baz) == "object", "Object property preserved");
|
||||
let baz = val.baz;
|
||||
ok("number" in baz && baz.number == 1, "Primite inside object preserved");
|
||||
ok("arr" in baz && Array.isArray(baz.arr), "Array inside object is preserved");
|
||||
checkBlob(baz.arr[0]);
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure("Getting object");
|
||||
},
|
||||
function() {
|
||||
let req = mozSettings.createLock().clear();
|
||||
req.onsuccess = function() {
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure("Deleting database");
|
||||
},
|
||||
function () {
|
||||
ok(true, "all done!\n");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
];
|
||||
|
||||
function next() {
|
||||
try {
|
||||
let step = steps.shift();
|
||||
if (step) {
|
||||
step();
|
||||
}
|
||||
} catch(ex) {
|
||||
ok(false, "Caught exception", ex);
|
||||
}
|
||||
}
|
||||
|
||||
function permissionTest() {
|
||||
if (gSettingsEnabled) {
|
||||
next();
|
||||
} else {
|
||||
is(mozSettings, null, "mozSettings is null when not enabled.");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
let gSettingsEnabled = SpecialPowers.getBoolPref("dom.mozSettings.enabled");
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(permissionTest);
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
Загрузка…
Ссылка в новой задаче