This commit is contained in:
Phil Ringnalda 2014-03-23 08:43:23 -07:00
Родитель 6dc6e3896f d3cfb61572
Коммит 9493e2fb24
55 изменённых файлов: 1101 добавлений и 214 удалений

Просмотреть файл

@ -418,6 +418,7 @@ pref("dom.global-constructor.disable.mozContact", false);
pref("dom.phonenumber.substringmatching.BR", 8);
pref("dom.phonenumber.substringmatching.CO", 10);
pref("dom.phonenumber.substringmatching.VE", 7);
pref("dom.phonenumber.substringmatching.CL", 8);
// WebAlarms
pref("dom.mozAlarms.enabled", true);

Просмотреть файл

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e6702f8786633bbbe27ee5cbc00a31f7e2f60a8f"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="06cfe08cd72f32404f304d34fb902b544bdfeb9e"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>

Просмотреть файл

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e6702f8786633bbbe27ee5cbc00a31f7e2f60a8f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="06cfe08cd72f32404f304d34fb902b544bdfeb9e"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="cb16958e41105d7c551d9941f522db97b8312538"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>

Просмотреть файл

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="a9e08b91e9cd1f0930f16cfc49ec72f63575d5fe">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e6702f8786633bbbe27ee5cbc00a31f7e2f60a8f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="06cfe08cd72f32404f304d34fb902b544bdfeb9e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="cb16958e41105d7c551d9941f522db97b8312538"/>

Просмотреть файл

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e6702f8786633bbbe27ee5cbc00a31f7e2f60a8f"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="06cfe08cd72f32404f304d34fb902b544bdfeb9e"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>

Просмотреть файл

@ -4,6 +4,6 @@
"branch": "",
"revision": ""
},
"revision": "4926fae1778461d93ff10b0fe4f8430246373e03",
"revision": "4dff379346b266bd93f48291a64cfc90af5d7daa",
"repo_path": "/integration/gaia-central"
}

Просмотреть файл

@ -17,7 +17,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e6702f8786633bbbe27ee5cbc00a31f7e2f60a8f"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="06cfe08cd72f32404f304d34fb902b544bdfeb9e"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>

Просмотреть файл

@ -15,7 +15,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e6702f8786633bbbe27ee5cbc00a31f7e2f60a8f"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="06cfe08cd72f32404f304d34fb902b544bdfeb9e"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>

Просмотреть файл

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e6702f8786633bbbe27ee5cbc00a31f7e2f60a8f"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="06cfe08cd72f32404f304d34fb902b544bdfeb9e"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>

Просмотреть файл

@ -17,7 +17,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e6702f8786633bbbe27ee5cbc00a31f7e2f60a8f"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="06cfe08cd72f32404f304d34fb902b544bdfeb9e"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>

Просмотреть файл

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e6702f8786633bbbe27ee5cbc00a31f7e2f60a8f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="06cfe08cd72f32404f304d34fb902b544bdfeb9e"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="cb16958e41105d7c551d9941f522db97b8312538"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>

Просмотреть файл

@ -17,7 +17,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e6702f8786633bbbe27ee5cbc00a31f7e2f60a8f"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="06cfe08cd72f32404f304d34fb902b544bdfeb9e"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>

Просмотреть файл

@ -6875,12 +6875,18 @@ let gRemoteTabsUI = {
* @return True if an existing tab was found, false otherwise
*/
function switchToTabHavingURI(aURI, aOpenNew, aOpenParams) {
// Certain URLs can be switched to irrespective of the source or destination
// window being in private browsing mode:
const kPrivateBrowsingWhitelist = new Set([
"about:customizing",
]);
// This will switch to the tab in aWindow having aURI, if present.
function switchIfURIInWindow(aWindow) {
// Only switch to the tab if neither the source and desination window are
// private and they are not in permanent private borwsing mode
if ((PrivateBrowsingUtils.isWindowPrivate(window) ||
PrivateBrowsingUtils.isWindowPrivate(aWindow)) &&
// Only switch to the tab if neither the source nor the destination window
// are private and they are not in permanent private browsing mode
if (!kPrivateBrowsingWhitelist.has(aURI.spec) &&
(PrivateBrowsingUtils.isWindowPrivate(window) ||
PrivateBrowsingUtils.isWindowPrivate(aWindow)) &&
!PrivateBrowsingUtils.permanentPrivateBrowsing) {
return false;
}

Просмотреть файл

@ -770,7 +770,6 @@ const CustomizableWidgets = [{
elem.section = aSection;
elem.value = item.value;
elem.setAttribute("class", "subviewbutton");
addShortcut(item, doc, elem);
containerElem.appendChild(elem);
}
},

Просмотреть файл

@ -12,7 +12,6 @@ const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource:///modules/SignInToWebsite.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "AboutHome",
"resource:///modules/AboutHome.jsm");
@ -88,6 +87,11 @@ XPCOMUtils.defineLazyModuleGetter(this, "BrowserUITelemetry",
XPCOMUtils.defineLazyModuleGetter(this, "AsyncShutdown",
"resource://gre/modules/AsyncShutdown.jsm");
#ifdef NIGHTLY_BUILD
XPCOMUtils.defineLazyModuleGetter(this, "SignInToWebsiteUX",
"resource:///modules/SignInToWebsite.jsm");
#endif
const PREF_PLUGINS_NOTIFYUSER = "plugins.update.notifyUser";
const PREF_PLUGINS_UPDATEURL = "plugins.update.url";
@ -472,7 +476,11 @@ BrowserGlue.prototype = {
PageThumbs.init();
NewTabUtils.init();
BrowserNewTabPreloader.init();
SignInToWebsiteUX.init();
#ifdef NIGHTLY_BUILD
if (Services.prefs.getBoolPref("dom.identity.enabled")) {
SignInToWebsiteUX.init();
}
#endif
PdfJs.init();
#ifdef NIGHTLY_BUILD
ShumwayUtils.init();
@ -655,7 +663,11 @@ BrowserGlue.prototype = {
BrowserNewTabPreloader.uninit();
CustomizationTabPreloader.uninit();
WebappManager.uninit();
SignInToWebsiteUX.uninit();
#ifdef NIGHTLY_BUILD
if (Services.prefs.getBoolPref("dom.identity.enabled")) {
SignInToWebsiteUX.uninit();
}
#endif
webrtcUI.uninit();
},

Просмотреть файл

@ -186,7 +186,7 @@
</vbox>
<vbox id="noFxaAccount">
<label value="&welcome.description;"/>
<label>&welcome.description;</label>
<label class="text-link"
onclick="gSyncPane.signUp(); return false;"
value="&welcome.createAccount.label;"/>

Просмотреть файл

@ -9,6 +9,9 @@ function test() {
initNetMonitor(FILTERING_URL).then(([aTab, aDebuggee, aMonitor]) => {
info("Starting test... ");
// It seems that this test may be slow on Ubuntu builds running on ec2.
requestLongerTimeout(2);
let { $, NetMonitorView } = aMonitor.panelWin;
let { RequestsMenu } = NetMonitorView;

Просмотреть файл

@ -7,7 +7,7 @@
<Description>Find photos, movies, music, and text to rip, sample, mash, and share.</Description>
<InputEncoding>utf-8</InputEncoding>
<Image width="16" height="16">data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAJUSURBVDiNjZO9S1thGMXPvTfJFbnkipNkLLS0ksFg0M0lf4CboNCEgIIg/RiKtEOn0qGWTtbVoBYcIji10I9J0ApWCjp0kRaXdhHjTW4+uGnur4NJ8GOwZ3nf4TnnfZ5z3scAdBGGYdyVdN+yrGHTNNOtVqsVhuG+pO+S3gE/LtV3BIxzPDJNc8FxHGN0dNRKpVIGoJ2dndr+/r5Vr9cl6bmkN0AoSQIEyHXdj5KYnZ3F932uolKpkM/nK5KQ9FmSCZwLOI7zQBLr6+vXiFdRLBaDtsiTTve3YrFYkM/nbyR3MDU1dSKpLumO+vr6Xruui+d5AFSrVVZWVtjY2KDRaABwdHTE4uIie3t7AJTLZaLRaFXSCyUSid1MJgOA53n09/eTTqdJJpPMzc2xurqKbduMj48Tj8fZ3d0FYHBw8FjSezmOU56fnwdgeXkZ27ap1WpUKhWazSZjY2Nks1kASqVSd4zp6eljSX/MtiHdRDpnEATyfb+bkiSVSqXu3TCM8xgHBga+dkY4OzvDdV2GhoZIJBLMzMxQKBSIRqNkMhlisRhbW1sAJJPJn5I+KB6Pv7poou/7rK2tsbm5SRAEXROXlpY4ODgAoFarYdu2J+llN8ZcLvffMeZyud+SGpLuCVBPT89jSRQKhRvJxWKxISmU9JTOT5Rk9Pb2fpHE5OQkJycn14inp6dMTEx4bdM/SbKAy8sk6WEkElmwLCuSSqUYGRmxgHB7e7t+eHgYazabgaRnkt7SeZnr63xbUtYwjGHTNNNhGP4F9iR9a6/zr4v1/wDE1D9XlC4rrAAAAABJRU5ErkJggg==</Image>
<Url type="text/html" method="GET" template="http://search.creativecommons.org/">
<Url type="text/html" method="GET" template="http://search.creativecommons.org/" resultdomain="creativecommons.org">
<Param name="q" value="{searchTerms}"/>
<Param name="sourceid" value="Mozilla-search"/>
</Url>

Просмотреть файл

@ -11,7 +11,7 @@
<Param name="s" value="0"/>
<Param name="q" value="{searchTerms}"/>
</Url>
<Url type="text/html" method="GET" template="http://rover.ebay.com/rover/1/711-47294-18009-3/4">
<Url type="text/html" method="GET" template="http://rover.ebay.com/rover/1/711-47294-18009-3/4" resultdomain="ebay.com">
<Param name="mpre" value="http://shop.ebay.com/?_nkw={searchTerms}"/>
</Url>
<SearchForm>http://search.ebay.com/</SearchForm>

Просмотреть файл

@ -11,7 +11,7 @@
<Param name="action" value="opensearch"/>
<Param name="search" value="{searchTerms}"/>
</Url>
<Url type="text/html" method="GET" template="http://en.wikipedia.org/wiki/Special:Search">
<Url type="text/html" method="GET" template="http://en.wikipedia.org/wiki/Special:Search" resultdomain="wikipedia.org">
<Param name="search" value="{searchTerms}"/>
<Param name="sourceid" value="Mozilla-search"/>
</Url>

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -16,7 +16,6 @@ EXTRA_JS_MODULES += [
'NetworkPrioritizer.jsm',
'offlineAppCache.jsm',
'SharedFrame.jsm',
'SignInToWebsite.jsm',
'SitePermissions.jsm',
'Social.jsm',
'TabCrashReporter.jsm',
@ -31,6 +30,11 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
'WindowsPreviewPerTab.jsm',
]
if CONFIG['NIGHTLY_BUILD']:
EXTRA_JS_MODULES += [
'SignInToWebsite.jsm',
]
EXTRA_PP_JS_MODULES += [
'AboutHome.jsm',
'RecentWindow.jsm',

Просмотреть файл

@ -267,12 +267,22 @@ function test_auth() {
function test() {
waitForExplicitFinish();
let sitw = {};
try {
Components.utils.import("resource:///modules/SignInToWebsite.jsm", sitw);
} catch (ex) {
ok(true, "Skip the test since SignInToWebsite.jsm isn't packaged outside outside mozilla-central");
finish();
return;
}
registerCleanupFunction(cleanUp);
let sitw = {};
Components.utils.import("resource:///modules/SignInToWebsite.jsm", sitw);
ok(sitw.SignInToWebsiteUX, "SignInToWebsiteUX object exists");
if (!Services.prefs.getBoolPref("dom.identity.enabled")) {
// If the pref isn't enabled then init wasn't called so do that for the test.
sitw.SignInToWebsiteUX.init();
}
// Replace implementation of ID Service functions for testing
window.selectIdentity = sitw.SignInToWebsiteUX.selectIdentity;
@ -317,6 +327,9 @@ function cleanUp() {
Components.utils.import("resource:///modules/SignInToWebsite.jsm", sitw);
sitw.SignInToWebsiteUX.selectIdentity = window.selectIdentity;
delete window.selectIdentity;
if (!Services.prefs.getBoolPref("dom.identity.enabled")) {
sitw.SignInToWebsiteUX.uninit();
}
Services.prefs.clearUserPref("toolkit.identity.debug");
}

Просмотреть файл

@ -13,6 +13,7 @@ skip-if = (toolkit == 'gonk' && debug) #debug-only failure
[test_contacts_international.html]
[test_contacts_substringmatching.html]
[test_contacts_substringmatchingVE.html]
[test_contacts_substringmatchingCL.html]
[test_migration.html]
support-files =
test_migration_chrome.js

Просмотреть файл

@ -402,15 +402,17 @@ function next() {
}
}
SimpleTest.waitForExplicitFinish();
function start_tests() {
// Skip tests on Android < 4.0 due to test failures on tbpl (see bugs 897924 & 888891)
let androidVersion = SpecialPowers.Cc['@mozilla.org/system-info;1']
.getService(SpecialPowers.Ci.nsIPropertyBag2)
.getProperty('version');
if (!isAndroid || androidVersion >= 14) {
SimpleTest.waitForExplicitFinish();
addLoadEvent(next);
next();
} else {
ok(true, "Skip tests on Android < 4.0 (bugs 897924 & 888891");
SimpleTest.finish();
}
}

Просмотреть файл

@ -43,13 +43,13 @@ var properties2 = {
};
var number3 = {
international1: "0041557932012345",
international2: "+557932012345"
local: "7932012345",
international: "+557932012345"
};
var properties3 = {
name: ["Testname2"],
tel: [{value: number3.international2}]
tel: [{value: number3.international}]
};
var req;
@ -95,9 +95,9 @@ var steps = [
filterValue: number1.local};
req = mozContacts.find(options);
req.onsuccess = function () {
ok(req.result.length == 1, "Found exactly 1 contact.");
ise(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
ise(findResult1.id, sample_id1, "Same ID");
next();
};
req.onerror = onFailure;
@ -109,7 +109,7 @@ var steps = [
filterValue: number1.international};
req = mozContacts.find(options);
req.onsuccess = function () {
ok(req.result.length == 0, "Found exactly 0 contacts.");
ise(req.result.length, 0, "Found exactly 0 contacts.");
next();
};
req.onerror = onFailure;
@ -122,7 +122,7 @@ var steps = [
filterValue: shortNumber};
req = mozContacts.find(options);
req.onsuccess = function() {
ok(req.result.length == 0, "The prefix short number should not match any contact.");
ise(req.result.length, 0, "The prefix short number should not match any contact.");
next();
};
req.onerror = onFailure;
@ -135,7 +135,7 @@ var steps = [
filterValue: shortNumber};
req = mozContacts.find(options);
req.onsuccess = function() {
ok(req.result.length == 0, "The suffix short number should not match any contact.");
ise(req.result.length, 0, "The suffix short number should not match any contact.");
next();
};
req.onerror = onFailure;
@ -147,7 +147,7 @@ var steps = [
filterValue: shortNumber};
req = mozContacts.find(options);
req.onsuccess = function() {
ok(req.result.length == 1, "Found the contact equally matching the shortNumber.");
ise(req.result.length, 1, "Found the contact equally matching the shortNumber.");
next();
};
req.onerror = onFailure;
@ -171,7 +171,7 @@ var steps = [
filterValue: number1.local};
req = mozContacts.find(options);
req.onsuccess = function () {
ok(req.result.length == 0, "Found exactly 0 contact.");
ise(req.result.length, 0, "Found exactly 0 contact.");
next();
};
req.onerror = onFailure;
@ -183,7 +183,7 @@ var steps = [
filterValue: number1.international};
req = mozContacts.find(options);
req.onsuccess = function () {
ok(req.result.length == 0, "Found exactly 0 contact.");
ise(req.result.length, 0, "Found exactly 0 contact.");
next();
};
req.onerror = onFailure;
@ -195,9 +195,9 @@ var steps = [
filterValue: number2.local};
req = mozContacts.find(options);
req.onsuccess = function () {
ok(req.result.length == 1, "Found exactly 1 contact.");
ise(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
ise(findResult1.id, sample_id1, "Same ID");
next();
};
req.onerror = onFailure;
@ -209,7 +209,7 @@ var steps = [
filterValue: number2.international};
req = mozContacts.find(options);
req.onsuccess = function () {
ok(req.result.length == 0, "Found exactly 1 contact.");
ise(req.result.length, 0, "Found exactly 1 contact.");
next();
};
req.onerror = onFailure;
@ -224,7 +224,7 @@ var steps = [
req.onerror = onFailure;
},
function () {
ok(true, "Adding a new contact with country code");
ok(true, "Adding a contact with a Brazilian country code");
createResult1 = new mozContact(properties3);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
@ -235,15 +235,15 @@ var steps = [
req.onerror = onFailure;
},
function () {
ok(true, "Searching for international number with prefix");
ok(true, "Searching for Brazilian number using local number");
var options = {filterBy: ["tel"],
filterOp: "match",
filterValue: number3.international1};
filterValue: number3.local};
req = mozContacts.find(options);
req.onsuccess = function () {
ok(req.result.length == 1, "Found exactly 1 contact.");
ise(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
ise(findResult1.id, sample_id1, "Same ID");
next();
};
req.onerror = onFailure;
@ -263,7 +263,11 @@ var steps = [
}
];
start_tests();
SpecialPowers.pushPrefEnv({
set: [
["ril.lastKnownSimMcc", "000"]
]
}, start_tests);
</script>
</pre>
</body>

Просмотреть файл

@ -45,6 +45,15 @@ var prop4 = {
tel: [{ value: "(0414) 233-9888" }]
};
var brazilianNumber = {
international1: "0041557932012345",
international2: "+557932012345"
};
var prop5 = {
tel: [{value: brazilianNumber.international2}]
};
var req;
var steps = [
function () {
@ -293,6 +302,40 @@ var steps = [
}
req.onerror = onFailure;
},
function () {
ok(true, "Adding a new contact with a Brazilian country code");
createResult1 = new mozContact(prop5);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
sample_id1 = createResult1.id;
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Searching for international number with prefix");
var options = {filterBy: ["tel"],
filterOp: "match",
filterValue: brazilianNumber.international1};
req = mozContacts.find(options);
req.onsuccess = function () {
ok(req.result.length == 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Deleting database");
req = mozContacts.clear()
req.onsuccess = function () {
ok(true, "Deleted the database");
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "all done!\n");
SpecialPowers.clearUserPref("dom.phonenumber.substringmatching.BR");

Просмотреть файл

@ -0,0 +1,204 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=877302
-->
<head>
<title>Test for Bug 949537 substring matching for WebContacts</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=949537">Mozilla Bug 949537</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script>
<script class="testbody" type="text/javascript">
"use strict";
var landlineNumber = "+56 2 27654321";
var number = {
local: "87654321",
international: "+56 9 87654321"
};
var properties = {
name: ["Testname2"],
tel: [{value: number.international}]
};
var req;
var steps = [
function () {
ok(true, "Adding a contact with a Chilean number");
createResult1 = new mozContact(properties);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
sample_id1 = createResult1.id;
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Searching for Chilean number with prefix");
req = mozContacts.find({
filterBy: ["tel"],
filterOp: "match",
filterValue: number.international
});
req.onsuccess = function () {
ise(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ise(findResult1.id, sample_id1, "Same ID");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Searching for Chilean number using local number");
req = mozContacts.find({
filterBy: ["tel"],
filterOp: "match",
filterValue: number.local
});
req.onsuccess = function () {
ise(req.result.length, 1, "Found 0 contacts.");
next();
};
req.onerror = onFailure;
},
clearDatabase,
function () {
ok(true, "Adding contact with mobile number");
createResult1 = new mozContact({tel: [{value: number.international}]});
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
sample_id1 = createResult1.id;
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving all contacts");
req = mozContacts.find({});
req.onsuccess = function () {
ise(req.result.length, 1, "One contact.");
findResult1 = req.result[0];
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by last 8 digits");
req = mozContacts.find({
filterBy: ["tel"],
filterOp: "match",
filterValue: number.international.slice(-8)
});
req.onsuccess = function () {
ise(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ise(findResult1.id, sample_id1, "Same ID");
ise(findResult1.tel[0].value, number.international, "Same Value");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by last 9 digits");
req = mozContacts.find({
filterBy: ["tel"],
filterOp: "match",
filterValue: number.international.slice(-9)
});
req.onsuccess = function () {
ise(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ise(findResult1.id, sample_id1, "Same ID");
ise(findResult1.tel[0].value, number.international, "Same Value");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by last 6 digits");
req = mozContacts.find({
filterBy: ["tel"],
filterOp: "match",
filterValue: number.international.slice(-6)
});
req.onsuccess = function () {
ise(req.result.length, 0, "Found exactly zero contacts.");
next();
};
req.onerror = onFailure;
},
clearDatabase,
function () {
ok(true, "Adding contact with landline number");
createResult1 = new mozContact({tel: [{value: landlineNumber}]});
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
sample_id1 = createResult1.id;
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving all contacts");
req = mozContacts.find({});
req.onsuccess = function () {
ise(req.result.length, 1, "One contact.");
findResult1 = req.result[0];
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by last 7 digits (local number) with landline calling prefix");
req = mozContacts.find({
filterBy: ["tel"],
filterOp: "match",
filterValue: "022" + landlineNumber.slice(-7)
});
req.onsuccess = function () {
ise(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ise(findResult1.id, sample_id1, "Same ID");
ise(findResult1.tel[0].value, landlineNumber, "Same Value");
next();
};
req.onerror = onFailure;
},
clearDatabase,
function () {
ok(true, "all done!\n");
SimpleTest.finish();
}
];
SpecialPowers.pushPrefEnv({
set: [
["dom.phonenumber.substringmatching.CL", 8],
["ril.lastKnownSimMcc", "730"]
]
}, start_tests);
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1574,6 +1574,16 @@ nsXPCComponents_utils_Sandbox::CallOrConstruct(nsIXPConnectWrappedNative *wrappe
if (NS_FAILED(AssembleSandboxMemoryReporterName(cx, options.sandboxName)))
return ThrowAndFail(NS_ERROR_INVALID_ARG, cx, _retval);
if (options.metadata.isNullOrUndefined()) {
// If the caller is running in a sandbox, inherit.
RootedObject callerGlobal(cx, CurrentGlobalOrNull(cx));
if (IsSandbox(callerGlobal)) {
rv = GetSandboxMetadata(cx, callerGlobal, &options.metadata);
if (NS_WARN_IF(NS_FAILED(rv)))
return rv;
}
}
rv = CreateSandboxObject(cx, args.rval(), prinOrSop, options);
if (NS_FAILED(rv))

Просмотреть файл

@ -41,5 +41,16 @@ function run_test()
}
do_check_eq(thrown, true);
sandbox = Components.utils.Sandbox(this, {
metadata: { foopy: { bar: 2 }, baz: "hi" }
});
let inner = Components.utils.evalInSandbox("Components.utils.Sandbox('http://www.blah.com')", sandbox);
metadata = Components.utils.getSandboxMetadata(inner);
do_check_eq(metadata.baz, "hi");
do_check_eq(metadata.foopy.bar, 2);
metadata.baz = "foo";
}

Просмотреть файл

@ -0,0 +1,80 @@
===================
Firefox for Android
===================
UI Telemetry
============
Fennec records UI events using a telemetry framework called UITelemetry.
Some links:
- `Project page <https://wiki.mozilla.org/Mobile/Projects/Telemetry_probes_for_Fennec_UI_elements>`_
- `Wiki page <https://wiki.mozilla.org/Mobile/Fennec/Android/UITelemetry>`_
- `User research notes <https://wiki.mozilla.org/Mobile/User_Experience/Research>`_
Sessions
--------
**Sessions** are essentially scopes. They are meant to provide context to
events; this allows events to be simpler and more reusable. Sessions are
usually bound to some component of the UI, some user action with a duration, or
some transient state.
For example, a session might be begun when a user begins interacting with a
menu, and stopped when the interaction ends. Or a session might encapsulate
period of no network connectivity, the first five seconds after the browser
launched, the time spent with an active download, or a guest mode session.
Sessions implicitly record the duration of the interaction.
A simple use-case for sessions is the bookmarks panel in about:home. We start a
session when the user swipes into the panel, and stop it when they swipe away.
This bookmarks session does two things: firstly, it gives scope to any generic
event that may occur within the panel (*e.g.*, loading a URL). Secondly, it
allows us to figure out how much time users are spending in the bookmarks
panel.
To start a session, call ``Telemetry.startUISession(String sessionName)``.
Session names should be brief, lowercase, and should describe which UI
component the user is interacting with. In certain cases where the UI component
is dynamic, they could include an ID, essential to identifying that component.
An example of this is dynamic home panels: we use session names of the format
``homepanel:<panel_id>`` to identify home panel sessions.
To stop a session call ``Telemetry.stopUISession(String sessionName, String
reason)``. ``sessionName`` is the name of the open session and ``reason`` is a
descriptive cause for the ending of the session. It should be brief, lowercase,
and generic so it can be reused in different places. Examples reasons are:
``switched``
The user transitioned to a UI element of equal level.
``exit``
The user left for an entirely different element.
Events
------
Events capture key occurrences. They should be brief and simple, and should not contain sensitive or excess information. Context for events should come from the session (scope). An event can be created with four fields (via ``Telemetry.sendUIEvent``): ``action``, ``method``, ``extras``, and ``timestamp``.
``action``
The name of the event. Should be brief and lowercase. If needed, you can make use of namespacing with a '``.``' separator. Example event names: ``panel.switch``, ``panel.enable``, ``panel.disable``, ``panel.install``.
``method`` (Optional)
Used for user actions that can be performed in many ways. This field specifies the method by which the action was performed. For example, users can add an item to their reading list either by long-tapping the reader icon in the address bar, or from within reader mode. We would use the same event name for both user actions but specify two methods: ``addressbar`` and ``readermode``.
``extras`` (Optional)
For extra information that may be useful in understanding the event. Make an effort to keep this brief.
``timestamp`` (Optional)
The time at which the event occurred. If not specified, this field defaults to the current value of the realtime clock.
Clock
-----
Times are relative to either elapsed realtime (an arbitrary monotonically increasing clock that continues to tick when the device is asleep), or elapsed uptime (which doesn't tick when the device is in deep sleep). We default to elapsed realtime.
See the documentation in `the source <http://mxr.mozilla.org/mozilla-central/source/mobile/android/base/Telemetry.java>`_ for more details.

Просмотреть файл

@ -5,6 +5,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DIRS += ['locales']
SPHINX_TREES['fennec'] = 'docs'
include('android-services.mozbuild')

Просмотреть файл

@ -22,7 +22,7 @@ interface nsISearchSubmission : nsISupports
readonly attribute nsIURI uri;
};
[scriptable, uuid(7914c4b8-f05b-40c9-a982-38a058cd1769)]
[scriptable, uuid(77de6680-57ec-4105-a183-cc7cf7e84b09)]
interface nsISearchEngine : nsISupports
{
/**
@ -157,6 +157,18 @@ interface nsISearchEngine : nsISupports
*/
readonly attribute AString identifier;
/**
* Gets a string representing the hostname from which search results for a
* given responseType are returned, minus the leading "www." (if present).
* This can be specified as an url attribute in the engine description file,
* but will default to host from the <Url>'s template otherwise.
*
* @param responseType [optional]
* The MIME type to get resultDomain for. Defaults to "text/html".
*
* @return the resultDomain for the given responseType.
*/
AString getResultDomain([optional] in AString responseType);
};
[scriptable, uuid(9fc39136-f08b-46d3-b232-96f4b7b0e235)]

Просмотреть файл

@ -428,7 +428,7 @@ function BookmarksStore(name, engine) {
// Explicitly nullify our references to our cached services so we don't leak
Svc.Obs.add("places-shutdown", function() {
for each ([query, stmt] in Iterator(this._stmts)) {
for each (let [query, stmt] in Iterator(this._stmts)) {
stmt.finalize();
}
this._stmts = {};

Просмотреть файл

@ -25,6 +25,24 @@ XPCOMUtils.defineLazyModuleGetter(this, "Deprecated",
XPCOMUtils.defineLazyGetter(this, "gTextDecoder", () => new TextDecoder());
XPCOMUtils.defineLazyGetter(this, "gTextEncoder", () => new TextEncoder());
/**
* Generates an hash for the given string.
*
* @note The generated hash is returned in base64 form. Mind the fact base64
* is case-sensitive if you are going to reuse this code.
*/
function generateHash(aString) {
let cryptoHash = Cc["@mozilla.org/security/hash;1"]
.createInstance(Ci.nsICryptoHash);
cryptoHash.init(Ci.nsICryptoHash.MD5);
let stringStream = Cc["@mozilla.org/io/string-input-stream;1"]
.createInstance(Ci.nsIStringInputStream);
stringStream.data = aString;
cryptoHash.updateFromStream(stringStream, -1);
// base64 allows the '/' char, but we can't use it for filenames.
return cryptoHash.finish(true).replace("/", "-", "g");
}
this.BookmarkJSONUtils = Object.freeze({
/**
* Import bookmarks from a url.
@ -99,13 +117,19 @@ this.BookmarkJSONUtils = Object.freeze({
*
* @param aFilePath
* OS.File path string for the "bookmarks.json" file to be created.
*
* @param [optional] aOptions
* Object containing options for the export:
* - failIfHashIs: if the generated file would have the same hash
* defined here, will reject with ex.becauseSameHash
* @return {Promise}
* @resolves To the exported bookmarks count when the file has been created.
* @resolves once the file has been created, to an object with the
* following properties:
* - count: number of exported bookmarks
* - hash: file hash for contents comparison
* @rejects JavaScript exception.
* @deprecated passing an nsIFile is deprecated
*/
exportToFile: function BJU_exportToFile(aFilePath) {
exportToFile: function BJU_exportToFile(aFilePath, aOptions={}) {
if (aFilePath instanceof Ci.nsIFile) {
Deprecated.warning("Passing an nsIFile to BookmarksJSONUtils.exportToFile " +
"is deprecated. Please use an OS.File path string instead.",
@ -125,12 +149,29 @@ this.BookmarkJSONUtils = Object.freeze({
Components.utils.reportError("Unable to report telemetry.");
}
startTime = Date.now();
let hash = generateHash(jsonString);
// Report the time taken to generate the hash.
try {
Services.telemetry
.getHistogramById("PLACES_BACKUPS_HASHING_MS")
.add(Date.now() - startTime);
} catch (ex) {
Components.utils.reportError("Unable to report telemetry.");
}
if (hash === aOptions.failIfHashIs) {
let e = new Error("Hash conflict");
e.becauseSameHash = true;
throw e;
}
// Do not write to the tmp folder, otherwise if it has a different
// filesystem writeAtomic will fail. Eventual dangling .tmp files should
// be cleaned up by the caller.
yield OS.File.writeAtomic(aFilePath, jsonString,
{ tmpPath: OS.Path.join(aFilePath + ".tmp") });
return count;
return { count: count, hash: hash };
});
},

Просмотреть файл

@ -28,12 +28,71 @@ XPCOMUtils.defineLazyGetter(this, "localFileCtor",
() => Components.Constructor("@mozilla.org/file/local;1",
"nsILocalFile", "initWithPath"));
XPCOMUtils.defineLazyGetter(this, "filenamesRegex",
() => new RegExp("^bookmarks-([0-9\-]+)(?:_([0-9]+)){0,1}(?:_([a-z0-9=\+\-]{24})){0,1}\.(json|html)", "i")
);
/**
* Appends meta-data information to a given filename.
*/
function appendMetaDataToFilename(aFilename, aMetaData) {
let matches = aFilename.match(filenamesRegex);
return "bookmarks-" + matches[1] +
"_" + aMetaData.count +
"_" + aMetaData.hash +
"." + matches[4];
}
/**
* Gets the hash from a backup filename.
*
* @return the extracted hash or null.
*/
function getHashFromFilename(aFilename) {
let matches = aFilename.match(filenamesRegex);
if (matches && matches[3])
return matches[3];
return null;
}
/**
* Given two filenames, checks if they contain the same date.
*/
function isFilenameWithSameDate(aSourceName, aTargetName) {
let sourceMatches = aSourceName.match(filenamesRegex);
let targetMatches = aTargetName.match(filenamesRegex);
return sourceMatches && targetMatches &&
sourceMatches[1] == targetMatches[1] &&
sourceMatches[4] == targetMatches[4];
}
/**
* Given a filename, searches for another backup with the same date.
*
* @return OS.File path string or null.
*/
function getBackupFileForSameDate(aFilename) {
return Task.spawn(function* () {
let backupFiles = yield PlacesBackups.getBackupFiles();
for (let backupFile of backupFiles) {
if (isFilenameWithSameDate(OS.Path.basename(backupFile), aFilename))
return backupFile;
}
return null;
});
}
this.PlacesBackups = {
get _filenamesRegex() {
delete this._filenamesRegex;
return this._filenamesRegex =
new RegExp("^(bookmarks)-([0-9-]+)(_[0-9]+)*\.(json|html)");
},
/**
* Matches the backup filename:
* 0: file name
* 1: date in form Y-m-d
* 2: bookmarks count
* 3: contents hash
* 4: file extension
*/
get filenamesRegex() filenamesRegex,
get folder() {
Deprecated.warning(
@ -99,8 +158,7 @@ this.PlacesBackups = {
let entry = files.getNext().QueryInterface(Ci.nsIFile);
// A valid backup is any file that matches either the localized or
// not-localized filename (bug 445704).
let matches = entry.leafName.match(this._filenamesRegex);
if (!entry.isHidden() && matches) {
if (!entry.isHidden() && filenamesRegex.test(entry.leafName)) {
// Remove bogus backups in future dates.
if (this.getDateForFile(entry) > new Date()) {
entry.remove(false);
@ -139,8 +197,7 @@ this.PlacesBackups = {
return;
}
let matches = aEntry.name.match(this._filenamesRegex);
if (matches) {
if (filenamesRegex.test(aEntry.name)) {
// Remove bogus backups in future dates.
let filePath = aEntry.path;
if (this.getDateForFile(filePath) > new Date()) {
@ -188,10 +245,10 @@ this.PlacesBackups = {
getDateForFile: function PB_getDateForFile(aBackupFile) {
let filename = (aBackupFile instanceof Ci.nsIFile) ? aBackupFile.leafName
: OS.Path.basename(aBackupFile);
let matches = filename.match(this._filenamesRegex);
let matches = filename.match(filenamesRegex);
if (!matches)
throw("Invalid backup file name: " + filename);
return new Date(matches[2].replace(/-/g, "/"));
return new Date(matches[1].replace(/-/g, "/"));
},
/**
@ -258,7 +315,8 @@ this.PlacesBackups = {
aFilePath = aFilePath.path;
}
return Task.spawn(function* () {
let nodeCount = yield BookmarkJSONUtils.exportToFile(aFilePath);
let { count: nodeCount, hash: hash } =
yield BookmarkJSONUtils.exportToFile(aFilePath);
let backupFolderPath = yield this.getBackupFolder();
if (OS.Path.dirname(aFilePath) == backupFolderPath) {
@ -274,22 +332,33 @@ this.PlacesBackups = {
// we also want to copy this new backup to it.
// This way we ensure the latest valid backup is the same saved by the
// user. See bug 424389.
let name = this.getFilenameForDate();
let newFilename = this._appendMetaDataToFilename(name,
{ nodeCount: nodeCount });
let newFilePath = OS.Path.join(backupFolderPath, newFilename);
let backupFile = yield this._getBackupFileForSameDate(name);
if (!backupFile) {
// Update internal cache if we are not replacing an existing
// backup file.
this._entries.unshift(new localFileCtor(newFilePath));
if (!this._backupFiles) {
yield this.getBackupFiles();
let mostRecentBackupFile = yield this.getMostRecentBackup("json");
if (!mostRecentBackupFile ||
hash != getHashFromFilename(OS.Path.basename(mostRecentBackupFile))) {
let name = this.getFilenameForDate();
let newFilename = appendMetaDataToFilename(name,
{ count: nodeCount,
hash: hash });
let newFilePath = OS.Path.join(backupFolderPath, newFilename);
let backupFile = yield getBackupFileForSameDate(name);
if (backupFile) {
// There is already a backup for today, replace it.
yield OS.File.remove(backupFile, { ignoreAbsent: true });
if (!this._backupFiles)
yield this.getBackupFiles();
else
this._backupFiles.shift();
this._backupFiles.unshift(newFilePath);
} else {
// There is no backup for today, add the new one.
this._entries.unshift(new localFileCtor(newFilePath));
if (!this._backupFiles)
yield this.getBackupFiles();
this._backupFiles.unshift(newFilePath);
}
this._backupFiles.unshift(newFilePath);
}
yield OS.File.copy(aFilePath, newFilePath);
yield OS.File.copy(aFilePath, newFilePath);
}
}
return nodeCount;
@ -303,83 +372,90 @@ this.PlacesBackups = {
* "places/excludeFromBackup".
*
* @param [optional] int aMaxBackups
* The maximum number of backups to keep.
* The maximum number of backups to keep. If set to 0
* all existing backups are removed and aForceBackup is
* ignored, so a new one won't be created.
* @param [optional] bool aForceBackup
* Forces creating a backup even if one was already
* created that day (overwrites).
* @return {Promise}
*/
create: function PB_create(aMaxBackups, aForceBackup) {
let limitBackups = function* () {
let backupFiles = yield this.getBackupFiles();
if (typeof aMaxBackups == "number" && aMaxBackups > -1 &&
backupFiles.length >= aMaxBackups) {
let numberOfBackupsToDelete = backupFiles.length - aMaxBackups;
while (numberOfBackupsToDelete--) {
this._entries.pop();
let oldestBackup = this._backupFiles.pop();
yield OS.File.remove(oldestBackup);
}
}
}.bind(this);
return Task.spawn(function* () {
// Construct the new leafname.
if (aMaxBackups === 0) {
// Backups are disabled, delete any existing one and bail out.
yield limitBackups(0);
return;
}
// Ensure to initialize _backupFiles
if (!this._backupFiles)
yield this.getBackupFiles();
let newBackupFilename = this.getFilenameForDate();
let mostRecentBackupFile = yield this.getMostRecentBackup();
// If we already have a backup for today we should do nothing, unless we
// were required to enforce a new backup.
let backupFile = yield getBackupFileForSameDate(newBackupFilename);
if (backupFile && !aForceBackup)
return;
if (!aForceBackup) {
let backupFiles = yield this.getBackupFiles();
// If there are backups, limit them to aMaxBackups, if requested.
if (backupFiles.length > 0 && typeof aMaxBackups == "number" &&
aMaxBackups > -1 && backupFiles.length >= aMaxBackups) {
let numberOfBackupsToDelete = backupFiles.length - aMaxBackups;
// If we don't have today's backup, remove one more so that
// the total backups after this operation does not exceed the
// number specified in the pref.
if (!this._isFilenameWithSameDate(OS.Path.basename(mostRecentBackupFile),
newBackupFilename)) {
numberOfBackupsToDelete++;
}
while (numberOfBackupsToDelete--) {
this._entries.pop();
let oldestBackup = this._backupFiles.pop();
yield OS.File.remove(oldestBackup);
}
}
// Do nothing if we already have this backup or we don't want backups.
if (aMaxBackups === 0 ||
(mostRecentBackupFile &&
this._isFilenameWithSameDate(OS.Path.basename(mostRecentBackupFile),
newBackupFilename)))
return;
}
let backupFile = yield this._getBackupFileForSameDate(newBackupFilename);
if (backupFile) {
if (aForceBackup) {
yield OS.File.remove(backupFile, { ignoreAbsent: true });
} else {
return;
}
// In case there is a backup for today we should recreate it.
this._backupFiles.shift();
this._entries.shift();
yield OS.File.remove(backupFile, { ignoreAbsent: true });
}
// Now check the hash of the most recent backup, and try to create a new
// backup, if that fails due to hash conflict, just rename the old backup.
let mostRecentBackupFile = yield this.getMostRecentBackup();
let mostRecentHash = mostRecentBackupFile &&
getHashFromFilename(OS.Path.basename(mostRecentBackupFile));
// Save bookmarks to a backup file.
let backupFolder = yield this.getBackupFolder();
let newBackupFile = OS.Path.join(backupFolder, newBackupFilename);
let nodeCount = yield this.saveBookmarksToJSONFile(newBackupFile);
// Rename the filename with metadata.
let newFilenameWithMetaData = this._appendMetaDataToFilename(
newBackupFilename,
{ nodeCount: nodeCount });
let newFilenameWithMetaData;
try {
let { count: nodeCount, hash: hash } =
yield BookmarkJSONUtils.exportToFile(newBackupFile,
{ failIfHashIs: mostRecentHash });
newFilenameWithMetaData = appendMetaDataToFilename(newBackupFilename,
{ count: nodeCount,
hash: hash });
} catch (ex if ex.becauseSameHash) {
// The last backup already contained up-to-date information, just
// rename it as if it was today's backup.
this._backupFiles.shift();
this._entries.shift();
newBackupFile = mostRecentBackupFile;
newFilenameWithMetaData = appendMetaDataToFilename(
newBackupFilename,
{ count: this.getBookmarkCountForFile(mostRecentBackupFile),
hash: mostRecentHash });
}
// Append metadata to the backup filename.
let newBackupFileWithMetadata = OS.Path.join(backupFolder, newFilenameWithMetaData);
yield OS.File.move(newBackupFile, newBackupFileWithMetadata);
// Update internal cache.
let newFileWithMetaData = new localFileCtor(newBackupFileWithMetadata);
this._entries.pop();
this._entries.unshift(newFileWithMetaData);
this._backupFiles.pop();
this._entries.unshift(new localFileCtor(newBackupFileWithMetadata));
this._backupFiles.unshift(newBackupFileWithMetadata);
}.bind(this));
},
_appendMetaDataToFilename:
function PB__appendMetaDataToFilename(aFilename, aMetaData) {
let matches = aFilename.match(this._filenamesRegex);
let newFilename = matches[1] + "-" + matches[2] + "_" +
aMetaData.nodeCount + "." + matches[4];
return newFilename;
// Limit the number of backups.
yield limitBackups(aMaxBackups);
}.bind(this));
},
/**
@ -393,43 +469,12 @@ this.PlacesBackups = {
getBookmarkCountForFile: function PB_getBookmarkCountForFile(aFilePath) {
let count = null;
let filename = OS.Path.basename(aFilePath);
let matches = filename.match(this._filenamesRegex);
if (matches && matches[3])
count = matches[3].replace(/_/g, "");
let matches = filename.match(filenamesRegex);
if (matches && matches[2])
count = matches[2];
return count;
},
_isFilenameWithSameDate:
function PB__isFilenameWithSameDate(aSourceName, aTargetName) {
let sourceMatches = aSourceName.match(this._filenamesRegex);
let targetMatches = aTargetName.match(this._filenamesRegex);
return (sourceMatches && targetMatches &&
sourceMatches[1] == targetMatches[1] &&
sourceMatches[2] == targetMatches[2] &&
sourceMatches[4] == targetMatches[4]);
},
_getBackupFileForSameDate:
function PB__getBackupFileForSameDate(aFilename) {
return Task.spawn(function* () {
let backupFolderPath = yield this.getBackupFolder();
let iterator = new OS.File.DirectoryIterator(backupFolderPath);
let backupFile;
yield iterator.forEach(function(aEntry) {
if (this._isFilenameWithSameDate(aEntry.name, aFilename)) {
backupFile = aEntry.path;
return iterator.close();
}
}.bind(this));
yield iterator.close();
return backupFile;
}.bind(this));
},
/**
* Gets a bookmarks tree representation usable to create backups in different
* file formats. The root or the tree is PlacesUtils.placesRootId.

Просмотреть файл

@ -0,0 +1,142 @@
/* 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";
this.EXPORTED_SYMBOLS = [ "PriorityUrlProvider" ];
const Ci = Components.interfaces;
const Cc = Components.classes;
const Cu = Components.utils;
const Cr = Components.results;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/Task.jsm");
/**
* Provides search engines matches to the PriorityUrlProvider through the
* search engines definitions handled by the Search Service.
*/
const SEARCH_ENGINE_TOPIC = "browser-search-engine-modified";
let SearchEnginesProvider = {
init: function () {
this._engines = new Map();
let deferred = Promise.defer();
Services.search.init(rv => {
if (Components.isSuccessCode(rv)) {
Services.search.getVisibleEngines().forEach(this._addEngine, this);
deferred.resolve();
} else {
deferred.reject(new Error("Unable to initialize search service."));
}
});
Services.obs.addObserver(this, SEARCH_ENGINE_TOPIC, true);
return deferred.promise;
},
observe: function (engine, topic, verb) {
let engine = engine.QueryInterface(Ci.nsISearchEngine);
switch (verb) {
case "engine-added":
this._addEngine(engine);
break;
case "engine-changed":
if (engine.hidden) {
this._removeEngine(engine);
} else {
this._addEngine(engine);
}
break;
case "engine-removed":
this._removeEngine(engine);
break;
}
},
_addEngine: function (engine) {
if (this._engines.has(engine.name)) {
return;
}
let token = engine.getResultDomain();
if (!token) {
return;
}
let match = { token: token,
// TODO (bug 557665): searchForm should provide an usable
// url with affiliate code, if available.
url: engine.searchForm,
title: engine.name,
iconUrl: engine.iconURI ? engine.iconURI.spec : null,
reason: "search" }
this._engines.set(engine.name, match);
PriorityUrlProvider.addMatch(match);
},
_removeEngine: function (engine) {
if (!this._engines.has(engine.name)) {
return;
}
this._engines.delete(engine.name);
PriorityUrlProvider.removeMatchByToken(engine.getResultDomain());
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
Ci.nsISupportsWeakReference])
}
/**
* The PriorityUrlProvider allows to match a given string to a list of
* urls that should have priority in url search components, like autocomplete.
* Each returned match is an object with the following properties:
* - token: string used to match the search term to the url
* - url: url string represented by the match
* - title: title describing the match, or an empty string if not available
* - iconUrl: url of the icon associated to the match, or null if not available
* - reason: a string describing the origin of the match, for example if it
* represents a search engine, it will be "search".
*/
let matches = new Map();
let initialized = false;
function promiseInitialized() {
if (initialized) {
return Promise.resolve();
}
return Task.spawn(function* () {
try {
yield SearchEnginesProvider.init();
} catch (ex) {
Cu.reportError(ex);
}
initialized = true;
});
}
this.PriorityUrlProvider = Object.freeze({
addMatch: function (match) {
matches.set(match.token, match);
},
removeMatchByToken: function (token) {
matches.delete(token);
},
getMatchingSpec: function (searchToken) {
return Task.spawn(function* () {
yield promiseInitialized();
for (let [token, match] of matches.entries()) {
// Match at the beginning for now. In future an aOptions argument may
// allow to control the matching behavior.
if (token.startsWith(searchToken)) {
return match;
}
}
return null;
}.bind(this));
}
});

Просмотреть файл

@ -68,6 +68,7 @@ if CONFIG['MOZ_PLACES']:
'PlacesBackups.jsm',
'PlacesDBUtils.jsm',
'PlacesTransactions.jsm',
'PriorityUrlProvider.jsm'
]
EXTRA_PP_JS_MODULES += [

Просмотреть файл

@ -27,7 +27,6 @@ add_task(function check_max_backups_is_respected() {
// Allow 2 backups, the older one should be removed.
yield PlacesBackups.create(2);
let backupFilename = PlacesBackups.getFilenameForDate();
let re = new RegExp("^" + backupFilename.replace(/\.json/, "") + "(_[0-9]+){0,1}\.json$");
let count = 0;
let lastBackupPath = null;
@ -35,7 +34,7 @@ add_task(function check_max_backups_is_respected() {
try {
yield iterator.forEach(aEntry => {
count++;
if (aEntry.name.match(re))
if (PlacesBackups.filenamesRegex.test(aEntry.name))
lastBackupPath = aEntry.path;
});
} finally {
@ -56,7 +55,6 @@ add_task(function check_max_backups_greater_than_backups() {
// Allow 3 backups, none should be removed.
yield PlacesBackups.create(3);
let backupFilename = PlacesBackups.getFilenameForDate();
let re = new RegExp("^" + backupFilename.replace(/\.json/, "") + "(_[0-9]+){0,1}\.json$");
let count = 0;
let lastBackupPath = null;
@ -64,7 +62,7 @@ add_task(function check_max_backups_greater_than_backups() {
try {
yield iterator.forEach(aEntry => {
count++;
if (aEntry.name.match(re))
if (PlacesBackups.filenamesRegex.test(aEntry.name))
lastBackupPath = aEntry.path;
});
} finally {
@ -83,7 +81,6 @@ add_task(function check_max_backups_null() {
// since one for today already exists.
yield PlacesBackups.create(null);
let backupFilename = PlacesBackups.getFilenameForDate();
let re = new RegExp("^" + backupFilename.replace(/\.json/, "") + "(_[0-9]+){0,1}\.json$");
let count = 0;
let lastBackupPath = null;
@ -91,7 +88,7 @@ add_task(function check_max_backups_null() {
try {
yield iterator.forEach(aEntry => {
count++;
if (aEntry.name.match(re))
if (PlacesBackups.filenamesRegex.test(aEntry.name))
lastBackupPath = aEntry.path;
});
} finally {
@ -110,7 +107,6 @@ add_task(function check_max_backups_undefined() {
// since one for today already exists.
yield PlacesBackups.create();
let backupFilename = PlacesBackups.getFilenameForDate();
let re = new RegExp("^" + backupFilename.replace(/\.json/, "") + "(_[0-9]+){0,1}\.json$");
let count = 0;
let lastBackupPath = null;
@ -118,7 +114,7 @@ add_task(function check_max_backups_undefined() {
try {
yield iterator.forEach(aEntry => {
count++;
if (aEntry.name.match(re))
if (PlacesBackups.filenamesRegex.test(aEntry.name))
lastBackupPath = aEntry.path;
});
} finally {

Просмотреть файл

@ -22,11 +22,10 @@ function run_test() {
dateObj.setYear(dateObj.getFullYear() + 1);
let name = PlacesBackups.getFilenameForDate(dateObj);
do_check_eq(name, "bookmarks-" + dateObj.toLocaleFormat("%Y-%m-%d") + ".json");
let rx = new RegExp("^" + name.replace(/\.json/, "") + "(_[0-9]+){0,1}\.json$");
let files = bookmarksBackupDir.directoryEntries;
while (files.hasMoreElements()) {
let entry = files.getNext().QueryInterface(Ci.nsIFile);
if (entry.leafName.match(rx))
if (PlacesBackups.filenamesRegex.test(entry.leafName))
entry.remove(false);
}
@ -43,8 +42,7 @@ function run_test() {
let mostRecentBackupFile = yield PlacesBackups.getMostRecentBackup();
do_check_neq(mostRecentBackupFile, null);
let todayFilename = PlacesBackups.getFilenameForDate();
rx = new RegExp("^" + todayFilename.replace(/\.json/, "") + "(_[0-9]+){0,1}\.json$");
do_check_true(OS.Path.basename(mostRecentBackupFile).match(rx).length > 0);
do_check_true(PlacesBackups.filenamesRegex.test(OS.Path.basename(mostRecentBackupFile)));
// Check that future backup has been removed.
do_check_false(futureBackupFile.exists());

Просмотреть файл

@ -0,0 +1,59 @@
/* 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/. */
/**
* Checks that automatically created bookmark backups are discarded if they are
* duplicate of an existing ones.
*/
function run_test() {
run_next_test();
}
add_task(function() {
// Create a backup for yesterday in the backups folder.
let backupFolder = yield PlacesBackups.getBackupFolder();
let dateObj = new Date();
dateObj.setDate(dateObj.getDate() - 1);
let oldBackupName = PlacesBackups.getFilenameForDate(dateObj);
let oldBackup = OS.Path.join(backupFolder, oldBackupName);
let {count: count, hash: hash} = yield BookmarkJSONUtils.exportToFile(oldBackup);
do_check_true(count > 0);
do_check_eq(hash.length, 24);
oldBackupName = oldBackupName.replace(/\.json/, "_" + count + "_" + hash + ".json");
yield OS.File.move(oldBackup, OS.Path.join(backupFolder, oldBackupName));
// Create a backup.
// This should just rename the existing backup, so in the end there should be
// only one backup with today's date.
yield PlacesBackups.create();
// Get the hash of the generated backup
let backupFiles = yield PlacesBackups.getBackupFiles();
do_check_eq(backupFiles.length, 1);
let matches = OS.Path.basename(backupFiles[0]).match(PlacesBackups.filenamesRegex);
do_check_eq(matches[1], new Date().toLocaleFormat("%Y-%m-%d"));
do_check_eq(matches[2], count);
do_check_eq(matches[3], hash);
// Add a bookmark and create another backup.
let bookmarkId = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.bookmarks.bookmarksMenuFolder,
uri("http://foo.com"),
PlacesUtils.bookmarks.DEFAULT_INDEX,
"foo");
// We must enforce a backup since one for today already exists. The forced
// backup will replace the existing one.
yield PlacesBackups.create(undefined, true);
do_check_eq(backupFiles.length, 1);
recentBackup = yield PlacesBackups.getMostRecentBackup();
do_check_neq(recentBackup, OS.Path.join(backupFolder, oldBackupName));
matches = OS.Path.basename(recentBackup).match(PlacesBackups.filenamesRegex);
do_check_eq(matches[1], new Date().toLocaleFormat("%Y-%m-%d"));
do_check_eq(matches[2], count + 1);
do_check_neq(matches[3], hash);
// Clean up
PlacesUtils.bookmarks.removeItem(bookmarkId);
yield PlacesBackups.create(0);
});

Просмотреть файл

@ -31,9 +31,9 @@ add_task(function test_saveBookmarksToJSONFile_and_create()
// Ensure the backup would be copied to our backups folder when the original
// backup is saved somewhere else.
let recentBackup = yield PlacesBackups.getMostRecentBackup();
let todayFilename = PlacesBackups.getFilenameForDate();
do_check_eq(OS.Path.basename(recentBackup),
todayFilename.replace(/\.json/, "_" + nodeCount + ".json"));
let matches = OS.Path.basename(recentBackup).match(PlacesBackups.filenamesRegex);
do_check_eq(matches[2], nodeCount);
do_check_eq(matches[3].length, 24);
// Clear all backups in our backups folder.
yield PlacesBackups.create(0);
@ -45,9 +45,9 @@ add_task(function test_saveBookmarksToJSONFile_and_create()
mostRecentBackupFile = yield PlacesBackups.getMostRecentBackup();
do_check_neq(mostRecentBackupFile, null);
let rx = new RegExp("^" + todayFilename.replace(/\.json/, "") + "_([0-9]+)\.json$");
let matches = OS.Path.basename(recentBackup).match(rx);
do_check_true(matches.length > 0 && parseInt(matches[1]) == nodeCount);
matches = OS.Path.basename(recentBackup).match(PlacesBackups.filenamesRegex);
do_check_eq(matches[2], nodeCount);
do_check_eq(matches[3].length, 24);
// Cleanup
backupFile.remove(false);

Просмотреть файл

@ -29,3 +29,4 @@ tail =
[test_711914.js]
[test_protectRoots.js]
[test_818593-store-backup-metadata.js]
[test_818584-discard-duplicate-backups.js]

Просмотреть файл

@ -522,10 +522,9 @@ function check_JSON_backup(aIsAutomaticBackup) {
bookmarksBackupDir.append("bookmarkbackups");
let files = bookmarksBackupDir.directoryEntries;
let backup_date = new Date().toLocaleFormat("%Y-%m-%d");
let rx = new RegExp("^bookmarks-" + backup_date + "_[0-9]+\.json$");
while (files.hasMoreElements()) {
let entry = files.getNext().QueryInterface(Ci.nsIFile);
if (entry.leafName.match(rx)) {
if (PlacesBackups.filenamesRegex.test(entry.leafName)) {
profileBookmarksJSONFile = entry;
break;
}

Просмотреть файл

@ -0,0 +1,74 @@
/* 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/. */
Cu.import("resource://gre/modules/PriorityUrlProvider.jsm");
function run_test() {
run_next_test();
}
add_task(function* search_engine_match() {
let engine = yield promiseDefaultSearchEngine();
let token = engine.getResultDomain();
let match = yield PriorityUrlProvider.getMatchingSpec(token.substr(0, 1));
do_check_eq(match.url, engine.searchForm);
do_check_eq(match.title, engine.name);
do_check_eq(match.iconUrl, engine.iconURI ? engine.iconURI.spec : null);
do_check_eq(match.reason, "search");
});
add_task(function* no_match() {
do_check_eq(null, yield PriorityUrlProvider.getMatchingSpec("test"));
});
add_task(function* hide_search_engine_nomatch() {
let engine = yield promiseDefaultSearchEngine();
let token = engine.getResultDomain();
let promiseTopic = promiseSearchTopic("engine-changed");
Services.search.removeEngine(engine);
yield promiseTopic;
do_check_true(engine.hidden);
do_check_eq(null, yield PriorityUrlProvider.getMatchingSpec(token.substr(0, 1)));
});
add_task(function* add_search_engine_match() {
let promiseTopic = promiseSearchTopic("engine-added");
do_check_eq(null, yield PriorityUrlProvider.getMatchingSpec("bacon"));
Services.search.addEngineWithDetails("bacon", "", "bacon", "Search Bacon",
"GET", "http://www.bacon.moz/?search={searchTerms}");
yield promiseSearchTopic;
let match = yield PriorityUrlProvider.getMatchingSpec("bacon");
do_check_eq(match.url, "http://www.bacon.moz");
do_check_eq(match.title, "bacon");
do_check_eq(match.iconUrl, null);
do_check_eq(match.reason, "search");
});
add_task(function* remove_search_engine_nomatch() {
let engine = Services.search.getEngineByName("bacon");
let promiseTopic = promiseSearchTopic("engine-removed");
Services.search.removeEngine(engine);
yield promiseTopic;
do_check_eq(null, yield PriorityUrlProvider.getMatchingSpec("bacon"));
});
function promiseDefaultSearchEngine() {
let deferred = Promise.defer();
Services.search.init( () => {
deferred.resolve(Services.search.defaultEngine);
});
return deferred.promise;
}
function promiseSearchTopic(expectedVerb) {
let deferred = Promise.defer();
Services.obs.addObserver( function observe(subject, topic, verb) {
do_log_info("browser-search-engine-modified: " + verb);
if (verb == expectedVerb) {
Services.obs.removeObserver(observe, "browser-search-engine-modified");
deferred.resolve();
}
}, "browser-search-engine-modified", false);
return deferred.promise;
}

Просмотреть файл

@ -8,8 +8,6 @@
* Check for correct functionality of bookmarks backups
*/
const PREFIX = "bookmarks-";
const SUFFIX = ".json";
const NUMBER_OF_BACKUPS = 10;
function run_test() {
@ -40,7 +38,7 @@ add_task(function () {
// creation time.
// Create fake backups for the newest dates.
for (let i = dates.length - 1; i >= 0; i--) {
let backupFilename = PREFIX + dates[i] + SUFFIX;
let backupFilename = PlacesBackups.getFilenameForDate(new Date(dates[i]));
let backupFile = bookmarksBackupDir.clone();
backupFile.append(backupFilename);
backupFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, parseInt("0666", 8));
@ -61,10 +59,9 @@ add_task(function () {
let backupFile;
if (i > 0) {
let files = bookmarksBackupDir.directoryEntries;
let rx = new RegExp("^" + PREFIX + dates[i] + "(_[0-9]+){0,1}" + SUFFIX + "$");
while (files.hasMoreElements()) {
let entry = files.getNext().QueryInterface(Ci.nsIFile);
if (entry.leafName.match(rx)) {
if (PlacesBackups.filenamesRegex.test(entry.leafName)) {
backupFilename = entry.leafName;
backupFile = entry;
break;
@ -73,7 +70,7 @@ add_task(function () {
shouldExist = true;
}
else {
backupFilename = PREFIX + dates[i] + SUFFIX;
backupFilename = PlacesBackups.getFilenameForDate(new Date(dates[i]));
backupFile = bookmarksBackupDir.clone();
backupFile.append(backupFilename);
shouldExist = false;

Просмотреть файл

@ -64,6 +64,7 @@ skip-if = os == "android"
# Bug 676989: test hangs consistently on Android
skip-if = os == "android"
[test_async_history_api.js]
[test_async_transactions.js]
[test_autocomplete_stopSearch_no_throw.js]
[test_bookmark_catobs.js]
[test_bookmarks_json.js]
@ -86,6 +87,7 @@ fail-if = os == "android"
# Bug 676989: test hangs consistently on Android
skip-if = os == "android"
[test_getChildIndex.js]
[test_getPlacesInfo.js]
[test_history.js]
[test_history_autocomplete_tags.js]
[test_history_catobs.js]
@ -110,7 +112,11 @@ fail-if = os == "android"
skip-if = true
[test_null_interfaces.js]
[test_onItemChanged_tags.js]
[test_pageGuid_bookmarkGuid.js]
[test_placeURIs.js]
[test_PlacesUtils_asyncGetBookmarkIds.js]
[test_PlacesUtils_lazyobservers.js]
[test_placesTxn.js]
[test_preventive_maintenance.js]
# Bug 676989: test hangs consistently on Android
skip-if = os == "android"
@ -118,6 +124,7 @@ skip-if = os == "android"
# Bug 676989: test hangs consistently on Android
skip-if = os == "android"
[test_preventive_maintenance_runTasks.js]
[test_priorityUrlProvider.js]
[test_removeVisitsByTimeframe.js]
# Bug 676989: test hangs consistently on Android
skip-if = os == "android"
@ -126,16 +133,10 @@ skip-if = os == "android"
[test_sql_guid_functions.js]
[test_tag_autocomplete_search.js]
[test_tagging.js]
[test_telemetry.js]
[test_update_frecency_after_delete.js]
# Bug 676989: test hangs consistently on Android
skip-if = os == "android"
[test_utils_backups_create.js]
[test_utils_getURLsForContainerNode.js]
[test_utils_setAnnotationsFor.js]
[test_PlacesUtils_asyncGetBookmarkIds.js]
[test_PlacesUtils_lazyobservers.js]
[test_placesTxn.js]
[test_telemetry.js]
[test_getPlacesInfo.js]
[test_pageGuid_bookmarkGuid.js]
[test_async_transactions.js]

Просмотреть файл

@ -861,12 +861,14 @@ function ParamSubstitution(aParamValue, aSearchTerms, aEngine) {
* The URL to which search queries should be sent. For GET requests,
* must contain the string "{searchTerms}", to indicate where the user
* entered search terms should be inserted.
* @param aResultDomain
* The root domain for this URL. Defaults to the template's host.
*
* @see http://opensearch.a9.com/spec/1.1/querysyntax/#urltag
*
* @throws NS_ERROR_NOT_IMPLEMENTED if aType is unsupported.
*/
function EngineURL(aType, aMethod, aTemplate) {
function EngineURL(aType, aMethod, aTemplate, aResultDomain) {
if (!aType || !aMethod || !aTemplate)
FAIL("missing type, method or template for EngineURL!");
@ -898,6 +900,14 @@ function EngineURL(aType, aMethod, aTemplate) {
default:
FAIL("new EngineURL: template uses invalid scheme!", Cr.NS_ERROR_FAILURE);
}
// If no resultDomain was specified in the engine definition file, use the
// host from the template.
this.resultDomain = aResultDomain || templateURI.host;
// We never want to return a "www." prefix, so eventually strip it.
if (this.resultDomain.startsWith("www.")) {
this.resultDomain = this.resultDomain.substr(4);
}
}
EngineURL.prototype = {
@ -1018,7 +1028,8 @@ EngineURL.prototype = {
_serializeToJSON: function SRCH_EURL__serializeToJSON() {
var json = {
template: this.template,
rels: this.rels
rels: this.rels,
resultDomain: this.resultDomain
};
if (this.type != URLTYPE_SEARCH_HTML)
@ -1049,6 +1060,8 @@ EngineURL.prototype = {
url.setAttribute("template", this.template);
if (this.rels.length)
url.setAttribute("rel", this.rels.join(" "));
if (this.resultDomain)
url.setAttribute("resultDomain", this.resultDomain);
for (var i = 0; i < this.params.length; ++i) {
var param = aDoc.createElementNS(OPENSEARCH_NS_11, "Param");
@ -1770,9 +1783,10 @@ Engine.prototype = {
// specified
var method = aElement.getAttribute("method") || "GET";
var template = aElement.getAttribute("template");
var resultDomain = aElement.getAttribute("resultdomain");
try {
var url = new EngineURL(type, method, template);
var url = new EngineURL(type, method, template, resultDomain);
} catch (ex) {
FAIL("_parseURL: failed to add " + template + " as a URL",
Cr.NS_ERROR_FAILURE);
@ -2271,7 +2285,8 @@ Engine.prototype = {
for (let i = 0; i < aJson._urls.length; ++i) {
let url = aJson._urls[i];
let engineURL = new EngineURL(url.type || URLTYPE_SEARCH_HTML,
url.method || "GET", url.template);
url.method || "GET", url.template,
url.resultDomain);
engineURL._initWithJSON(url, this);
this._urls.push(engineURL);
}
@ -2719,6 +2734,25 @@ Engine.prototype = {
return (this._getURLOfType(type) != null);
},
// from nsISearchEngine
getResultDomain: function SRCH_ENG_getResultDomain(aResponseType) {
#ifdef ANDROID
if (!aResponseType) {
aResponseType = this._defaultMobileResponseType;
}
#endif
if (!aResponseType) {
aResponseType = URLTYPE_SEARCH_HTML;
}
LOG("getResultDomain: responseType: \"" + aResponseType + "\"");
let url = this._getURLOfType(aResponseType);
if (url)
return url.resultDomain;
return "";
},
// nsISupports
QueryInterface: function SRCH_ENG_QI(aIID) {
if (aIID.equals(Ci.nsISearchEngine) ||

Просмотреть файл

@ -5,7 +5,7 @@
<InputEncoding>UTF-8</InputEncoding>
<Image width="16" height="16">data:image/png;base64,AAABAAEAEBAAAAEAGABoAwAAFgAAACgAAAAQAAAAIAAAAAEAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADs9Pt8xetPtu9FsfFNtu%2BTzvb2%2B%2Fne4dFJeBw0egA%2FfAJAfAA8ewBBegAAAAD%2B%2FPtft98Mp%2BwWsfAVsvEbs%2FQeqvF8xO7%2F%2F%2F63yqkxdgM7gwE%2FggM%2BfQA%2BegBDeQDe7PIbotgQufcMufEPtfIPsvAbs%2FQvq%2Bfz%2Bf%2F%2B%2B%2FZKhR05hgBBhQI8hgBAgAI9ewD0%2B%2Fg3pswAtO8Cxf4Kw%2FsJvvYAqupKsNv%2B%2Fv7%2F%2FP5VkSU0iQA7jQA9hgBDgQU%2BfQH%2F%2Ff%2FQ6fM4sM4KsN8AteMCruIqqdbZ7PH8%2Fv%2Fg6Nc%2Fhg05kAA8jAM9iQI%2BhQA%2BgQDQu6b97uv%2F%2F%2F7V8Pqw3eiWz97q8%2Ff%2F%2F%2F%2F7%2FPptpkkqjQE4kwA7kAA5iwI8iAA8hQCOSSKdXjiyflbAkG7u2s%2F%2B%2F%2F39%2F%2F7r8utrqEYtjQE8lgA7kwA7kwA9jwA9igA9hACiWSekVRyeSgiYSBHx6N%2F%2B%2Fv7k7OFRmiYtlAA5lwI7lwI4lAA7kgI9jwE9iwI4iQCoVhWcTxCmb0K%2BooT8%2Fv%2F7%2F%2F%2FJ2r8fdwI1mwA3mQA3mgA8lAE8lAE4jwA9iwE%2BhwGfXifWvqz%2B%2Ff%2F58u%2Fev6Dt4tr%2B%2F%2F2ZuIUsggA7mgM6mAM3lgA5lgA6kQE%2FkwBChwHt4dv%2F%2F%2F728ei1bCi7VAC5XQ7kz7n%2F%2F%2F6bsZkgcB03lQA9lgM7kwA2iQktZToPK4r9%2F%2F%2F9%2F%2F%2FSqYK5UwDKZAS9WALIkFn%2B%2F%2F3%2F%2BP8oKccGGcIRJrERILYFEMwAAuEAAdX%2F%2Ff7%2F%2FP%2B%2BfDvGXQLIZgLEWgLOjlf7%2F%2F%2F%2F%2F%2F9QU90EAPQAAf8DAP0AAfMAAOUDAtr%2F%2F%2F%2F7%2B%2Fu2bCTIYwDPZgDBWQDSr4P%2F%2Fv%2F%2F%2FP5GRuABAPkAA%2FwBAfkDAPAAAesAAN%2F%2F%2B%2Fz%2F%2F%2F64g1C5VwDMYwK8Yg7y5tz8%2Fv%2FV1PYKDOcAAP0DAf4AAf0AAfYEAOwAAuAAAAD%2F%2FPvi28ymXyChTATRrIb8%2F%2F3v8fk6P8MAAdUCAvoAAP0CAP0AAfYAAO4AAACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAA</Image>
<Url type="application/x-suggestions+json" method="GET" template="http://suggestqueries.google.com/complete/search?output=firefox&amp;client=firefox&amp;hl={moz:locale}&amp;q={searchTerms}"/>
<Url type="text/html" method="GET" template="http://www.google.com/search">
<Url type="text/html" method="GET" template="http://www.google.com/search" resultdomain="google.com">
<Param name="q" value="{searchTerms}"/>
<Param name="ie" value="utf-8"/>
<Param name="oe" value="utf-8"/>
@ -15,7 +15,7 @@
<MozParam name="channel" condition="purpose" purpose="contextmenu" value="rcs"/>
<MozParam name="channel" condition="purpose" purpose="keyword" value="fflb"/>
</Url>
<Url type="application/x-moz-default-purpose" method="GET" template="http://www.google.com/search">
<Url type="application/x-moz-default-purpose" method="GET" template="http://www.google.com/search" resultdomain="purpose.google.com">
<Param name="q" value="{searchTerms}"/>
<MozParam name="client" condition="defaultEngine" trueValue="firefox-a" falseValue="firefox"/>
<!-- MozParam with a default value if purpose is not specified -->

Просмотреть файл

@ -24,6 +24,7 @@
},
{
"template": "http://www.google.com/search",
"resultDomain": "google.com",
"rels": [
],
"params": [
@ -64,6 +65,7 @@
},
{
"template": "http://www.google.com/search",
"resultDomain": "purpose.google.com",
"rels": [
],
"type": "application/x-moz-default-purpose",

Просмотреть файл

@ -5,7 +5,7 @@ Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/NetUtil.jsm");
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/FileUtils.jsm");
Components.utils.import("resource://gre/modules/Promise.jsm");
Components.utils.import("resource://testing-common/AppInfo.jsm");
const BROWSER_SEARCH_PREF = "browser.search.";

Просмотреть файл

@ -199,6 +199,7 @@ let EXPECTED_ENGINE = {
type: "text/html",
method: "GET",
template: "http://www.google.com/search",
resultDomain: "google.com",
params: [
{
"name": "q",
@ -250,6 +251,7 @@ let EXPECTED_ENGINE = {
type: "application/x-moz-default-purpose",
method: "GET",
template: "http://www.google.com/search",
resultDomain: "purpose.google.com",
params: [
{
"name": "q",

Просмотреть файл

@ -0,0 +1,79 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/*
* Tests getResultDomain API.
*/
"use strict";
const Ci = Components.interfaces;
Components.utils.import("resource://testing-common/httpd.js");
let waitForEngines = new Set([ "Test search engine",
"A second test engine",
"bacon" ]);
function promiseEnginesAdded() {
let deferred = Promise.defer();
let observe = function observe(aSubject, aTopic, aData) {
let engine = aSubject.QueryInterface(Ci.nsISearchEngine);
do_print("Observer: " + aData + " for " + engine.name);
if (aData != "engine-added") {
return;
}
waitForEngines.delete(engine.name);
if (waitForEngines.size > 0) {
return;
}
let engine1 = Services.search.getEngineByName("Test search engine");
do_check_eq(engine1.getResultDomain(), "google.com");
do_check_eq(engine1.getResultDomain("text/html"), "google.com");
do_check_eq(engine1.getResultDomain("application/x-moz-default-purpose"),
"purpose.google.com");
do_check_eq(engine1.getResultDomain("fake-response-type"), "");
let engine2 = Services.search.getEngineByName("A second test engine");
do_check_eq(engine2.getResultDomain(), "duckduckgo.com");
let engine3 = Services.search.getEngineByName("bacon");
do_check_eq(engine3.getResultDomain(), "bacon.moz");
deferred.resolve();
};
Services.obs.addObserver(observe, "browser-search-engine-modified", false);
do_register_cleanup(function cleanup() {
Services.obs.removeObserver(observe, "browser-search-engine-modified");
});
return deferred.promise;
}
function run_test() {
removeMetadata();
updateAppInfo();
run_next_test();
}
add_task(function* check_resultDomain() {
let httpServer = new HttpServer();
httpServer.start(-1);
httpServer.registerDirectory("/", do_get_cwd());
let baseUrl = "http://localhost:" + httpServer.identity.primaryPort;
do_register_cleanup(function cleanup() {
httpServer.stop(function() {});
});
let promise = promiseEnginesAdded();
Services.search.addEngine(baseUrl + "/data/engine.xml",
Ci.nsISearchEngine.DATA_XML,
null, false);
Services.search.addEngine(baseUrl + "/data/engine2.xml",
Ci.nsISearchEngine.DATA_XML,
null, false);
Services.search.addEngineWithDetails("bacon", "", "bacon", "Search Bacon",
"GET", "http://www.bacon.moz/?search={searchTerms}");
yield promise;
});

Просмотреть файл

@ -31,6 +31,7 @@ support-files =
[test_notifications.js]
[test_addEngine_callback.js]
[test_multipleIcons.js]
[test_resultDomain.js]
[test_serialize_file.js]
[test_async.js]
[test_sync.js]

Просмотреть файл

@ -2845,6 +2845,15 @@
"extended_statistics_ok": true,
"description": "PLACES: Time to convert and write bookmarks.html"
},
"PLACES_BACKUPS_HASHING_MS": {
"expires_in_version": "never",
"kind": "exponential",
"low": 50,
"high": 2000,
"n_buckets": 10,
"extended_statistics_ok": true,
"description": "PLACES: Time to calculate the md5 hash for a backup"
},
"FENNEC_FAVICONS_COUNT": {
"expires_in_version": "never",
"kind": "exponential",