зеркало из https://github.com/mozilla/gecko-dev.git
Bug 467890 - Support automatic updates for app-shipped search plugins. r=gavin
This commit is contained in:
Родитель
39a665c9c1
Коммит
fa15736f8e
|
@ -276,9 +276,6 @@ pref("browser.search.defaultenginename", "chrome://browser-region/locale/re
|
|||
// disable logging for the search service by default
|
||||
pref("browser.search.log", false);
|
||||
|
||||
// serialize search plugin XML
|
||||
pref("browser.search.cache.enabled", true);
|
||||
|
||||
// Ordering of Search Engines in the Engine list.
|
||||
pref("browser.search.order.1", "chrome://browser-region/locale/region.properties");
|
||||
pref("browser.search.order.2", "chrome://browser-region/locale/region.properties");
|
||||
|
|
|
@ -131,6 +131,7 @@ const MOZSEARCH_LOCALNAME = "SearchPlugin";
|
|||
|
||||
const URLTYPE_SUGGEST_JSON = "application/x-suggestions+json";
|
||||
const URLTYPE_SEARCH_HTML = "text/html";
|
||||
const URLTYPE_OPENSEARCH = "application/opensearchdescription+xml";
|
||||
|
||||
// Empty base document used to serialize engines to file.
|
||||
const EMPTY_DOC = "<?xml version=\"1.0\"?>\n" +
|
||||
|
@ -825,6 +826,7 @@ function EngineURL(aType, aMethod, aTemplate) {
|
|||
this.type = type;
|
||||
this.method = method;
|
||||
this.params = [];
|
||||
this.rels = [];
|
||||
// Don't serialize expanded mozparams
|
||||
this.mozparams = {};
|
||||
|
||||
|
@ -892,10 +894,15 @@ EngineURL.prototype = {
|
|||
return new Submission(makeURI(url), postData);
|
||||
},
|
||||
|
||||
_hasRelation: function SRC_EURL__hasRelation(aRel)
|
||||
this.rels.some(function(e) e == aRel.toLowerCase()),
|
||||
|
||||
_initWithJSON: function SRC_EURL__initWithJSON(aJson, aEngine) {
|
||||
if (!aJson.params)
|
||||
return;
|
||||
|
||||
this.rels = aJson.rels;
|
||||
|
||||
for (let i = 0; i < aJson.params.length; ++i) {
|
||||
let param = aJson.params[i];
|
||||
if (param.mozparam) {
|
||||
|
@ -922,6 +929,7 @@ EngineURL.prototype = {
|
|||
_serializeToJSON: function SRCH_EURL__serializeToJSON() {
|
||||
var json = {
|
||||
template: this.template,
|
||||
rels: this.rels
|
||||
};
|
||||
|
||||
if (this.type != URLTYPE_SEARCH_HTML)
|
||||
|
@ -950,6 +958,8 @@ EngineURL.prototype = {
|
|||
url.setAttribute("type", this.type);
|
||||
url.setAttribute("method", this.method);
|
||||
url.setAttribute("template", this.template);
|
||||
if (this.rels.length)
|
||||
url.setAttribute("rel", this.rels.join(" "));
|
||||
|
||||
for (var i = 0; i < this.params.length; ++i) {
|
||||
var param = aDoc.createElementNS(OPENSEARCH_NS_11, "Param");
|
||||
|
@ -1066,6 +1076,17 @@ Engine.prototype = {
|
|||
_iconUpdateURL: null,
|
||||
// A reference to the timer used for lazily serializing the engine to file
|
||||
_serializeTimer: null,
|
||||
// Whether this engine has been used since the cache was last recreated.
|
||||
__used: null,
|
||||
get _used() {
|
||||
if (!this.__used)
|
||||
this.__used = !!engineMetadataService.getAttr(this, "used");
|
||||
return this.__used;
|
||||
},
|
||||
set _used(aValue) {
|
||||
this.__used = aValue
|
||||
engineMetadataService.setAttr(this, "used", aValue);
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves the data from the engine's file. If the engine's dataType is
|
||||
|
@ -1299,6 +1320,29 @@ Engine.prototype = {
|
|||
engineMetadataService.setAttr(aEngine, "updatelastmodified",
|
||||
(new Date()).toUTCString());
|
||||
|
||||
// If we're updating an app-shipped engine, ensure that the updateURLs
|
||||
// are the same.
|
||||
if (engineToUpdate._isInAppDir) {
|
||||
let oldUpdateURL = engineToUpdate._updateURL;
|
||||
let newUpdateURL = aEngine._updateURL;
|
||||
let oldSelfURL = engineToUpdate._getURLOfType(URLTYPE_OPENSEARCH);
|
||||
if (oldSelfURL && oldSelfURL._hasRelation("self")) {
|
||||
oldUpdateURL = oldSelfURL.template;
|
||||
let newSelfURL = aEngine._getURLOfType(URLTYPE_OPENSEARCH);
|
||||
if (!newSelfURL || !newSelfURL._hasRelation("self")) {
|
||||
LOG("_onLoad: updateURL missing in updated engine for " +
|
||||
aEngine.name + " aborted");
|
||||
return;
|
||||
}
|
||||
newUpdateURL = newSelfURL.template;
|
||||
}
|
||||
|
||||
if (oldUpdateURL != newUpdateURL) {
|
||||
LOG("_onLoad: updateURLs do not match! Update of " + aEngine.name + " aborted");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the new engine's icon, if it doesn't yet have one.
|
||||
if (!aEngine._iconURI && engineToUpdate._iconURI)
|
||||
aEngine._iconURI = engineToUpdate._iconURI;
|
||||
|
@ -1308,8 +1352,10 @@ Engine.prototype = {
|
|||
aEngine._useNow = false;
|
||||
}
|
||||
|
||||
// Write the engine to file
|
||||
aEngine._serializeToFile();
|
||||
// Write the engine to file. For readOnly engines, they'll be stored in the
|
||||
// cache following the notification below.
|
||||
if (!aEngine._readOnly)
|
||||
aEngine._serializeToFile();
|
||||
|
||||
// Notify the search service of the successful load. It will deal with
|
||||
// updates by checking aEngine._engineToUpdate.
|
||||
|
@ -1375,8 +1421,9 @@ Engine.prototype = {
|
|||
// The engine might not have a file yet, if it's being downloaded,
|
||||
// because the request for the engine file itself (_onLoad) may not
|
||||
// yet be complete. In that case, this change will be written to
|
||||
// file when _onLoad is called.
|
||||
if (aEngine._file)
|
||||
// file when _onLoad is called. For readonly engines, we'll store
|
||||
// the changes in the cache once notified below.
|
||||
if (aEngine._file && !aEngine._readOnly)
|
||||
aEngine._serializeToFile();
|
||||
|
||||
notifyAction(aEngine, SEARCH_ENGINE_CHANGED);
|
||||
|
@ -1483,6 +1530,9 @@ Engine.prototype = {
|
|||
Cr.NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
if (aElement.hasAttribute("rel"))
|
||||
url.rels = aElement.getAttribute("rel").toLowerCase().split(/\s+/);
|
||||
|
||||
for (var i = 0; i < aElement.childNodes.length; ++i) {
|
||||
var param = aElement.childNodes[i];
|
||||
if (param.localName == "Param") {
|
||||
|
@ -2216,7 +2266,9 @@ Engine.prototype = {
|
|||
|
||||
get _hasUpdates() {
|
||||
// Whether or not the engine has an update URL
|
||||
return !!(this._updateURL || this._iconUpdateURL);
|
||||
let selfURL = this._getURLOfType(URLTYPE_OPENSEARCH);
|
||||
return !!(this._updateURL || this._iconUpdateURL || (selfURL &&
|
||||
selfURL._hasRelation("self")));
|
||||
},
|
||||
|
||||
get name() {
|
||||
|
@ -2271,6 +2323,12 @@ Engine.prototype = {
|
|||
if (!aResponseType)
|
||||
aResponseType = URLTYPE_SEARCH_HTML;
|
||||
|
||||
// Check for updates on the first use of an app-shipped engine
|
||||
if (this._isInAppDir && aResponseType == URLTYPE_SEARCH_HTML && !this._used) {
|
||||
this._used = true;
|
||||
engineUpdateService.update(this);
|
||||
}
|
||||
|
||||
var url = this._getURLOfType(aResponseType);
|
||||
|
||||
if (!url)
|
||||
|
@ -2604,6 +2662,8 @@ SearchService.prototype = {
|
|||
try {
|
||||
addedEngine = new Engine(file, dataType, !isWritable);
|
||||
addedEngine._initFromFile();
|
||||
if (addedEngine._used)
|
||||
addedEngine._used = false;
|
||||
} catch (ex) {
|
||||
LOG("_loadEnginesFromDir: Failed to load " + file.path + "!\n" + ex);
|
||||
continue;
|
||||
|
@ -3322,6 +3382,49 @@ var engineUpdateService = {
|
|||
Date.now() + milliseconds);
|
||||
},
|
||||
|
||||
update: function eus_Update(aEngine) {
|
||||
let engine = aEngine.wrappedJSObject;
|
||||
ULOG("update called for " + aEngine._name);
|
||||
if (!getBoolPref(BROWSER_SEARCH_PREF + "update", true) || !engine._hasUpdates)
|
||||
return;
|
||||
|
||||
// We use the cache to store updated app engines, so refuse to update if the
|
||||
// cache is disabled.
|
||||
if (engine._readOnly &&
|
||||
!getBoolPref(BROWSER_SEARCH_PREF + "cache.enabled", true))
|
||||
return;
|
||||
|
||||
let testEngine = null;
|
||||
let updateURL = engine._getURLOfType(URLTYPE_OPENSEARCH);
|
||||
let updateURI = (updateURL && updateURL._hasRelation("self")) ?
|
||||
updateURL.getSubmission("", engine).uri :
|
||||
makeURI(engine._updateURL);
|
||||
if (updateURI) {
|
||||
if (engine._isDefault && !updateURI.schemeIs("https")) {
|
||||
ULOG("Invalid scheme for default engine update");
|
||||
return;
|
||||
}
|
||||
|
||||
let dataType = engineMetadataService.getAttr(engine, "updatedatatype");
|
||||
if (!dataType) {
|
||||
ULOG("No loadtype to update engine!");
|
||||
return;
|
||||
}
|
||||
|
||||
ULOG("updating " + engine.name + " from " + updateURI.spec);
|
||||
testEngine = new Engine(updateURI, dataType, false);
|
||||
testEngine._engineToUpdate = engine;
|
||||
testEngine._initFromURI();
|
||||
} else
|
||||
ULOG("invalid updateURI");
|
||||
|
||||
if (engine._iconUpdateURL) {
|
||||
// If we're updating the engine too, use the new engine object,
|
||||
// otherwise use the existing engine object.
|
||||
(testEngine || engine)._setIcon(engine._iconUpdateURL, true);
|
||||
}
|
||||
},
|
||||
|
||||
notify: function eus_Notify(aTimer) {
|
||||
ULOG("notify called");
|
||||
|
||||
|
@ -3336,16 +3439,14 @@ var engineUpdateService = {
|
|||
ULOG("currentTime: " + currentTime);
|
||||
for each (engine in searchService.getEngines({})) {
|
||||
engine = engine.wrappedJSObject;
|
||||
if (!engine._hasUpdates || engine._readOnly)
|
||||
if (!engine._hasUpdates)
|
||||
continue;
|
||||
|
||||
ULOG("checking " + engine.name);
|
||||
|
||||
var expirTime = engineMetadataService.getAttr(engine, "updateexpir");
|
||||
var updateURL = engine._updateURL;
|
||||
var iconUpdateURL = engine._iconUpdateURL;
|
||||
ULOG("expirTime: " + expirTime + "\nupdateURL: " + updateURL +
|
||||
"\niconUpdateURL: " + iconUpdateURL);
|
||||
ULOG("expirTime: " + expirTime + "\nupdateURL: " + engine._updateURL +
|
||||
"\niconUpdateURL: " + engine._iconUpdateURL);
|
||||
|
||||
var engineExpired = expirTime <= currentTime;
|
||||
|
||||
|
@ -3356,27 +3457,7 @@ var engineUpdateService = {
|
|||
|
||||
ULOG(engine.name + " has expired");
|
||||
|
||||
var testEngine = null;
|
||||
|
||||
var updateURI = makeURI(updateURL);
|
||||
if (updateURI) {
|
||||
var dataType = engineMetadataService.getAttr(engine, "updatedatatype")
|
||||
if (!dataType) {
|
||||
ULOG("No loadtype to update engine!");
|
||||
continue;
|
||||
}
|
||||
|
||||
testEngine = new Engine(updateURI, dataType, false);
|
||||
testEngine._engineToUpdate = engine;
|
||||
testEngine._initFromURI();
|
||||
} else
|
||||
ULOG("invalid updateURI");
|
||||
|
||||
if (iconUpdateURL) {
|
||||
// If we're updating the engine too, use the new engine object,
|
||||
// otherwise use the existing engine object.
|
||||
(testEngine || engine)._setIcon(iconUpdateURL, true);
|
||||
}
|
||||
this.update(engine);
|
||||
|
||||
// Schedule the next update
|
||||
this.scheduleNextUpdate(engine);
|
||||
|
|
Загрузка…
Ссылка в новой задаче