This commit is contained in:
Nick Alexander 2013-11-14 22:41:14 -08:00
Родитель 003967689a 56e157765f
Коммит 512ba56709
277 изменённых файлов: 9957 добавлений и 2869 удалений

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

@ -18,4 +18,4 @@
# Modifying this file will now automatically clobber the buildbot machines \o/
#
Another Windows WebIDL clobber needed due to bug 928195
Another Windows WebIDL clobber needed due to bug 674741

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

@ -1,4 +1,4 @@
{
"revision": "d9e07db2d0512169f304985a070eade8e81e6ba7",
"revision": "88cc9854d6daff8c577e3867b95a1e523e429112",
"repo_path": "/integration/gaia-central"
}

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

@ -189,6 +189,9 @@
@BINPATH@/components/dom_geolocation.xpt
@BINPATH@/components/dom_media.xpt
@BINPATH@/components/dom_network.xpt
#ifdef MOZ_NFC
@BINPATH@/components/dom_nfc.xpt
#endif
@BINPATH@/components/dom_notification.xpt
@BINPATH@/components/dom_html.xpt
@BINPATH@/components/dom_indexeddb.xpt
@ -494,6 +497,13 @@
@BINPATH@/components/webvtt.xpt
@BINPATH@/components/WebVTT.manifest
@BINPATH@/components/WebVTTParserWrapper.js
#ifdef MOZ_NFC
@BINPATH@/components/nsNfc.manifest
@BINPATH@/components/nsNfc.js
@BINPATH@/components/Nfc.manifest
@BINPATH@/components/Nfc.js
@BINPATH@/components/NfcContentHelper.js
#endif
#ifdef MOZ_ENABLE_DBUS
@BINPATH@/components/@DLL_PREFIX@dbusservice@DLL_SUFFIX@
#endif

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

@ -1210,6 +1210,11 @@ pref("devtools.webconsole.fontSize", 0);
// be cleared each time page navigation happens.
pref("devtools.webconsole.persistlog", false);
// Web Console timestamp: |true| if you want the logs and instructions
// in the Web Console to display a timestamp, or |false| to not display
// any timestamps.
pref("devtools.webconsole.timestampMessages", false);
// The number of lines that are displayed in the web console for the Net,
// CSS, JS and Web Developer categories.
pref("devtools.hud.loglimit.network", 200);

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

@ -731,10 +731,6 @@ var gPluginHandler = {
let principal = contentWindow.document.nodePrincipal;
Services.perms.addFromPrincipal(principal, aPluginInfo.permissionString,
permission, expireType, expireTime);
if (aNewState == "block") {
return;
}
}
// Manually activate the plugins that would have been automatically
@ -752,19 +748,23 @@ var gPluginHandler = {
}
if (aPluginInfo.permissionString == pluginHost.getPermissionStringForType(plugin.actualType)) {
pluginFound = true;
if (gPluginHandler.canActivatePlugin(plugin)) {
let overlay = this.getPluginUI(plugin, "main");
if (overlay) {
overlay.removeEventListener("click", gPluginHandler._overlayClickListener, true);
if (aNewState == "block") {
plugin.reload(true);
} else {
if (gPluginHandler.canActivatePlugin(plugin)) {
let overlay = this.getPluginUI(plugin, "main");
if (overlay) {
overlay.removeEventListener("click", gPluginHandler._overlayClickListener, true);
}
plugin.playPlugin();
}
plugin.playPlugin();
}
}
}
// If there are no instances of the plugin on the page any more, what the
// user probably needs is for us to allow and then refresh.
if (!pluginFound) {
if (aNewState != "block" && !pluginFound) {
browser.reload();
}
},

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

@ -1514,6 +1514,7 @@ SocialStatus = {
"class": "social-panel-frame",
"id": notificationFrameId,
"tooltip": "aHTMLTooltip",
"context": "contentAreaContextMenu",
// work around bug 793057 - by making the panel roughly the final size
// we are more likely to have the anchor in the correct position.

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

@ -8,52 +8,6 @@ var gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Co
Components.utils.import("resource://gre/modules/Services.jsm");
// This listens for the next opened tab and checks it is of the right url.
// opencallback is called when the new tab is fully loaded
// closecallback is called when the tab is closed
function TabOpenListener(url, opencallback, closecallback) {
this.url = url;
this.opencallback = opencallback;
this.closecallback = closecallback;
gBrowser.tabContainer.addEventListener("TabOpen", this, false);
}
TabOpenListener.prototype = {
url: null,
opencallback: null,
closecallback: null,
tab: null,
browser: null,
handleEvent: function(event) {
if (event.type == "TabOpen") {
gBrowser.tabContainer.removeEventListener("TabOpen", this, false);
this.tab = event.originalTarget;
this.browser = this.tab.linkedBrowser;
gBrowser.addEventListener("pageshow", this, false);
} else if (event.type == "pageshow") {
if (event.target.location.href != this.url)
return;
gBrowser.removeEventListener("pageshow", this, false);
this.tab.addEventListener("TabClose", this, false);
var url = this.browser.contentDocument.location.href;
is(url, this.url, "Should have opened the correct tab");
this.opencallback(this.tab, this.browser.contentWindow);
} else if (event.type == "TabClose") {
if (event.originalTarget != this.tab)
return;
this.tab.removeEventListener("TabClose", this, false);
this.opencallback = null;
this.tab = null;
this.browser = null;
// Let the window close complete
executeSoon(this.closecallback);
this.closecallback = null;
}
}
};
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {

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

@ -9,52 +9,6 @@ var gRunNextTestAfterPluginRemoved = false;
Components.utils.import("resource://gre/modules/Services.jsm");
// This listens for the next opened tab and checks it is of the right url.
// opencallback is called when the new tab is fully loaded
// closecallback is called when the tab is closed
function TabOpenListener(url, opencallback, closecallback) {
this.url = url;
this.opencallback = opencallback;
this.closecallback = closecallback;
gBrowser.tabContainer.addEventListener("TabOpen", this, false);
}
TabOpenListener.prototype = {
url: null,
opencallback: null,
closecallback: null,
tab: null,
browser: null,
handleEvent: function(event) {
if (event.type == "TabOpen") {
gBrowser.tabContainer.removeEventListener("TabOpen", this, false);
this.tab = event.originalTarget;
this.browser = this.tab.linkedBrowser;
gBrowser.addEventListener("pageshow", this, false);
} else if (event.type == "pageshow") {
if (event.target.location.href != this.url)
return;
gBrowser.removeEventListener("pageshow", this, false);
this.tab.addEventListener("TabClose", this, false);
var url = this.browser.contentDocument.location.href;
is(url, this.url, "Should have opened the correct tab");
this.opencallback(this.tab, this.browser.contentWindow);
} else if (event.type == "TabClose") {
if (event.originalTarget != this.tab)
return;
this.tab.removeEventListener("TabClose", this, false);
this.opencallback = null;
this.tab = null;
this.browser = null;
// Let the window close complete
executeSoon(this.closecallback);
this.closecallback = null;
}
}
};
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {

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

@ -8,52 +8,6 @@ var gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Co
Components.utils.import("resource://gre/modules/Services.jsm");
// This listens for the next opened tab and checks it is of the right url.
// opencallback is called when the new tab is fully loaded
// closecallback is called when the tab is closed
function TabOpenListener(url, opencallback, closecallback) {
this.url = url;
this.opencallback = opencallback;
this.closecallback = closecallback;
gBrowser.tabContainer.addEventListener("TabOpen", this, false);
}
TabOpenListener.prototype = {
url: null,
opencallback: null,
closecallback: null,
tab: null,
browser: null,
handleEvent: function(event) {
if (event.type == "TabOpen") {
gBrowser.tabContainer.removeEventListener("TabOpen", this, false);
this.tab = event.originalTarget;
this.browser = this.tab.linkedBrowser;
gBrowser.addEventListener("pageshow", this, false);
} else if (event.type == "pageshow") {
if (event.target.location.href != this.url)
return;
gBrowser.removeEventListener("pageshow", this, false);
this.tab.addEventListener("TabClose", this, false);
var url = this.browser.contentDocument.location.href;
is(url, this.url, "Should have opened the correct tab");
this.opencallback(this.tab, this.browser.contentWindow);
} else if (event.type == "TabClose") {
if (event.originalTarget != this.tab)
return;
this.tab.removeEventListener("TabClose", this, false);
this.opencallback = null;
this.tab = null;
this.browser = null;
// Let the window close complete
executeSoon(this.closecallback);
this.closecallback = null;
}
}
};
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {

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

@ -90,8 +90,12 @@ function test() {
function doTest(aIsPrivateMode, aWindow, aCallback) {
aWindow.gBrowser.addEventListener("pageshow", function pageShown(event) {
if (event.target.location == "about:blank")
// If data: -url PAC file isn't loaded soon enough, we may get about:privatebrowsing loaded
if (event.target.location == "about:blank" ||
event.target.location == "about:privatebrowsing") {
aWindow.gBrowser.selectedBrowser.loadURI(testURI);
return;
}
aWindow.gBrowser.removeEventListener("pageshow", pageShown);
executeSoon(function () {

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

@ -93,7 +93,7 @@ let MessageListener = {
receiveMessage: function ({name, data: {id}}) {
switch (name) {
case "SessionStore:collectSessionHistory":
let history = SessionHistory.read(docShell);
let history = SessionHistory.collect(docShell);
if ("index" in history) {
let tabIndex = history.index - 1;
// Don't include private data. It's only needed when duplicating
@ -141,7 +141,7 @@ let SyncHandler = {
},
collectSessionHistory: function (includePrivateData) {
let history = SessionHistory.read(docShell);
let history = SessionHistory.collect(docShell);
if ("index" in history) {
let tabIndex = history.index - 1;
TextAndScrollData.updateFrame(history.entries[tabIndex],

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

@ -15,6 +15,8 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PrivacyLevel",
"resource:///modules/sessionstore/PrivacyLevel.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Utils",
"resource:///modules/sessionstore/Utils.jsm");
function debug(msg) {
Services.console.logStringMessage("SessionHistory: " + msg);
@ -36,8 +38,12 @@ XPCOMUtils.defineLazyGetter(this, "gPostData", function () {
* The external API exported by this module.
*/
this.SessionHistory = Object.freeze({
read: function (docShell, includePrivateData) {
return SessionHistoryInternal.read(docShell, includePrivateData);
collect: function (docShell, includePrivateData) {
return SessionHistoryInternal.collect(docShell, includePrivateData);
},
restore: function (docShell, tabData) {
SessionHistoryInternal.restore(docShell, tabData);
}
});
@ -53,7 +59,7 @@ let SessionHistoryInternal = {
* @param includePrivateData (optional)
* True to always include private data and skip any privacy checks.
*/
read: function (docShell, includePrivateData = false) {
collect: function (docShell, includePrivateData = false) {
let data = {entries: []};
let isPinned = docShell.isAppTab;
let webNavigation = docShell.QueryInterface(Ci.nsIWebNavigation);
@ -63,7 +69,7 @@ let SessionHistoryInternal = {
try {
for (let i = 0; i < history.count; i++) {
let shEntry = history.getEntryAtIndex(i, false);
let entry = this._serializeEntry(shEntry, includePrivateData, isPinned);
let entry = this.serializeEntry(shEntry, includePrivateData, isPinned);
data.entries.push(entry);
}
} catch (ex) {
@ -109,7 +115,7 @@ let SessionHistoryInternal = {
* The tab is pinned and should be treated differently for privacy.
* @return object
*/
_serializeEntry: function (shEntry, includePrivateData, isPinned) {
serializeEntry: function (shEntry, includePrivateData, isPinned) {
let entry = { url: shEntry.URI.spec };
// Save some bytes and don't include the title property
@ -152,7 +158,7 @@ let SessionHistoryInternal = {
// Collect post data for the current history entry.
try {
let postdata = this._serializePostData(shEntry, isPinned);
let postdata = this.serializePostData(shEntry, isPinned);
if (postdata) {
entry.postdata_b64 = postdata;
}
@ -163,7 +169,7 @@ let SessionHistoryInternal = {
// Collect owner data for the current history entry.
try {
let owner = this._serializeOwner(shEntry);
let owner = this.serializeOwner(shEntry);
if (owner) {
entry.owner_b64 = owner;
}
@ -197,7 +203,7 @@ let SessionHistoryInternal = {
break;
}
children.push(this._serializeEntry(child, includePrivateData, isPinned));
children.push(this.serializeEntry(child, includePrivateData, isPinned));
}
}
@ -218,7 +224,7 @@ let SessionHistoryInternal = {
* Whether the docShell is owned by a pinned tab.
* @return The base64 encoded post data.
*/
_serializePostData: function (shEntry, isPinned) {
serializePostData: function (shEntry, isPinned) {
let isHttps = shEntry.URI.schemeIs("https");
if (!shEntry.postData || !gPostData ||
!PrivacyLevel.canSave({isHttps: isHttps, isPinned: isPinned})) {
@ -250,7 +256,7 @@ let SessionHistoryInternal = {
* The session history entry.
* @return The base64 encoded owner data.
*/
_serializeOwner: function (shEntry) {
serializeOwner: function (shEntry) {
if (!shEntry.owner) {
return null;
}
@ -274,5 +280,166 @@ let SessionHistoryInternal = {
// is guaranteed to handle all chars in strings, including embedded
// nulls.
return btoa(String.fromCharCode.apply(null, ownerBytes));
}
},
/**
* Restores session history data for a given docShell.
*
* @param docShell
* The docShell that owns the session history.
* @param tabData
* The tabdata including all history entries.
*/
restore: function (docShell, tabData) {
let webNavigation = docShell.QueryInterface(Ci.nsIWebNavigation);
let history = webNavigation.sessionHistory;
if (history.count > 0) {
history.PurgeHistory(history.count);
}
history.QueryInterface(Ci.nsISHistoryInternal);
let idMap = { used: {} };
let docIdentMap = {};
for (let i = 0; i < tabData.entries.length; i++) {
//XXXzpao Wallpaper patch for bug 514751
if (!tabData.entries[i].url)
continue;
history.addEntry(this.deserializeEntry(tabData.entries[i],
idMap, docIdentMap), true);
}
},
/**
* Expands serialized history data into a session-history-entry instance.
*
* @param entry
* Object containing serialized history data for a URL
* @param idMap
* Hash for ensuring unique frame IDs
* @param docIdentMap
* Hash to ensure reuse of BFCache entries
* @returns nsISHEntry
*/
deserializeEntry: function (entry, idMap, docIdentMap) {
var shEntry = Cc["@mozilla.org/browser/session-history-entry;1"].
createInstance(Ci.nsISHEntry);
shEntry.setURI(Utils.makeURI(entry.url));
shEntry.setTitle(entry.title || entry.url);
if (entry.subframe)
shEntry.setIsSubFrame(entry.subframe || false);
shEntry.loadType = Ci.nsIDocShellLoadInfo.loadHistory;
if (entry.contentType)
shEntry.contentType = entry.contentType;
if (entry.referrer)
shEntry.referrerURI = Utils.makeURI(entry.referrer);
if (entry.isSrcdocEntry)
shEntry.srcdocData = entry.srcdocData;
if (entry.cacheKey) {
var cacheKey = Cc["@mozilla.org/supports-PRUint32;1"].
createInstance(Ci.nsISupportsPRUint32);
cacheKey.data = entry.cacheKey;
shEntry.cacheKey = cacheKey;
}
if (entry.ID) {
// get a new unique ID for this frame (since the one from the last
// start might already be in use)
var id = idMap[entry.ID] || 0;
if (!id) {
for (id = Date.now(); id in idMap.used; id++);
idMap[entry.ID] = id;
idMap.used[id] = true;
}
shEntry.ID = id;
}
if (entry.docshellID)
shEntry.docshellID = entry.docshellID;
if (entry.structuredCloneState && entry.structuredCloneVersion) {
shEntry.stateData =
Cc["@mozilla.org/docshell/structured-clone-container;1"].
createInstance(Ci.nsIStructuredCloneContainer);
shEntry.stateData.initFromBase64(entry.structuredCloneState,
entry.structuredCloneVersion);
}
if (entry.scroll) {
var scrollPos = (entry.scroll || "0,0").split(",");
scrollPos = [parseInt(scrollPos[0]) || 0, parseInt(scrollPos[1]) || 0];
shEntry.setScrollPosition(scrollPos[0], scrollPos[1]);
}
if (entry.postdata_b64) {
var postdata = atob(entry.postdata_b64);
var stream = Cc["@mozilla.org/io/string-input-stream;1"].
createInstance(Ci.nsIStringInputStream);
stream.setData(postdata, postdata.length);
shEntry.postData = stream;
}
let childDocIdents = {};
if (entry.docIdentifier) {
// If we have a serialized document identifier, try to find an SHEntry
// which matches that doc identifier and adopt that SHEntry's
// BFCacheEntry. If we don't find a match, insert shEntry as the match
// for the document identifier.
let matchingEntry = docIdentMap[entry.docIdentifier];
if (!matchingEntry) {
matchingEntry = {shEntry: shEntry, childDocIdents: childDocIdents};
docIdentMap[entry.docIdentifier] = matchingEntry;
}
else {
shEntry.adoptBFCacheEntry(matchingEntry.shEntry);
childDocIdents = matchingEntry.childDocIdents;
}
}
if (entry.owner_b64) {
var ownerInput = Cc["@mozilla.org/io/string-input-stream;1"].
createInstance(Ci.nsIStringInputStream);
var binaryData = atob(entry.owner_b64);
ownerInput.setData(binaryData, binaryData.length);
var binaryStream = Cc["@mozilla.org/binaryinputstream;1"].
createInstance(Ci.nsIObjectInputStream);
binaryStream.setInputStream(ownerInput);
try { // Catch possible deserialization exceptions
shEntry.owner = binaryStream.readObject(true);
} catch (ex) { debug(ex); }
}
if (entry.children && shEntry instanceof Ci.nsISHContainer) {
for (var i = 0; i < entry.children.length; i++) {
//XXXzpao Wallpaper patch for bug 514751
if (!entry.children[i].url)
continue;
// We're getting sessionrestore.js files with a cycle in the
// doc-identifier graph, likely due to bug 698656. (That is, we have
// an entry where doc identifier A is an ancestor of doc identifier B,
// and another entry where doc identifier B is an ancestor of A.)
//
// If we were to respect these doc identifiers, we'd create a cycle in
// the SHEntries themselves, which causes the docshell to loop forever
// when it looks for the root SHEntry.
//
// So as a hack to fix this, we restrict the scope of a doc identifier
// to be a node's siblings and cousins, and pass childDocIdents, not
// aDocIdents, to _deserializeHistoryEntry. That is, we say that two
// SHEntries with the same doc identifier have the same document iff
// they have the same parent or their parents have the same document.
shEntry.AddChild(this.deserializeEntry(entry.children[i], idMap,
childDocIdents), i);
}
}
return shEntry;
},
};

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

@ -117,6 +117,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "TextAndScrollData",
"resource:///modules/sessionstore/TextAndScrollData.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SessionFile",
"resource:///modules/sessionstore/SessionFile.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SessionHistory",
"resource:///modules/sessionstore/SessionHistory.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "TabAttributes",
"resource:///modules/sessionstore/TabAttributes.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "TabState",
@ -1346,10 +1348,10 @@ let SessionStoreInternal = {
let tab = aWindow.gBrowser.selectedTab;
// If __SS_restoreState is still on the browser and it is
// TAB_STATE_NEEDS_RESTORE, then then we haven't restored
// this tab yet. Explicitly call restoreTab to kick off the restore.
// this tab yet. Explicitly call restoreTabContent to kick off the restore.
if (tab.linkedBrowser.__SS_restoreState &&
tab.linkedBrowser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE)
this.restoreTab(tab);
this.restoreTabContent(tab);
// attempt to update the current URL we send in a crash report
this._updateCrashReportURL(aWindow);
@ -1477,7 +1479,7 @@ let SessionStoreInternal = {
// Remove the tab state from the cache.
// Note that we cannot simply replace the contents of the cache
// as |aState| can be an incomplete state that will be completed
// by |restoreHistoryPrecursor|.
// by |restoreTabs|.
let tabState = JSON.parse(aState);
if (!tabState) {
debug("Empty state argument");
@ -1508,7 +1510,7 @@ let SessionStoreInternal = {
TabStateCache.delete(aTab);
this._setWindowStateBusy(window);
this.restoreHistoryPrecursor(window, [aTab], [tabState], 0);
this.restoreTabs(window, [aTab], [tabState], 0);
},
duplicateTab: function ssi_duplicateTab(aWindow, aTab, aDelta = 0) {
@ -1528,8 +1530,8 @@ let SessionStoreInternal = {
aWindow.gBrowser.addTab(null, {relatedToCurrent: true, ownerTab: aTab}) :
aWindow.gBrowser.addTab();
this.restoreHistoryPrecursor(aWindow, [newTab], [tabState], 0,
true /* Load this tab right away. */);
this.restoreTabs(aWindow, [newTab], [tabState], 0,
true /* Load this tab right away. */);
return newTab;
},
@ -1608,7 +1610,7 @@ let SessionStoreInternal = {
let tab = tabbrowser.addTab();
// restore tab content
this.restoreHistoryPrecursor(aWindow, [tab], [closedTabState], 1);
this.restoreTabs(aWindow, [tab], [closedTabState], 1);
// restore the tab's position
tabbrowser.moveTabTo(tab, closedTab.pos);
@ -2227,7 +2229,7 @@ let SessionStoreInternal = {
TelemetryStopwatch.start("FX_SESSION_RESTORE_RESTORE_WINDOW_MS");
// We're not returning from this before we end up calling restoreHistoryPrecursor
// We're not returning from this before we end up calling restoreTabs
// for this window, so make sure we send the SSWindowStateBusy event.
this._setWindowStateBusy(aWindow);
@ -2325,7 +2327,7 @@ let SessionStoreInternal = {
// If overwriting tabs, we want to reset each tab's "restoring" state. Since
// we're overwriting those tabs, they should no longer be restoring. The
// tabs will be rebuilt and marked if they need to be restored after loading
// state (in restoreHistoryPrecursor).
// state (in restoreTabs).
// We also want to invalidate any cached information on the tab state.
if (overwriteTabs) {
for (let i = 0; i < tabbrowser.tabs.length; i++) {
@ -2380,7 +2382,7 @@ let SessionStoreInternal = {
this._windows[aWindow.__SSi]._closedTabs = winData._closedTabs || [];
}
this.restoreHistoryPrecursor(aWindow, tabs, winData.tabs,
this.restoreTabs(aWindow, tabs, winData.tabs,
(overwriteTabs ? (parseInt(winData.selected) || 1) : 0));
if (aState.scratchpads) {
@ -2474,7 +2476,7 @@ let SessionStoreInternal = {
return [aTabs, aTabData];
},
/**
* Manage history restoration for a window
* @param aWindow
@ -2489,9 +2491,8 @@ let SessionStoreInternal = {
* Flag to indicate whether the given set of tabs aTabs should be
* restored/loaded immediately even if restore_on_demand = true
*/
restoreHistoryPrecursor:
function ssi_restoreHistoryPrecursor(aWindow, aTabs, aTabData, aSelectTab,
aRestoreImmediately = false)
restoreTabs: function (aWindow, aTabs, aTabData, aSelectTab,
aRestoreImmediately = false)
{
var tabbrowser = aWindow.gBrowser;
@ -2553,6 +2554,17 @@ let SessionStoreInternal = {
// out of date now that we're restoring it.
TabState.dropPendingCollections(tab);
if (!tabData.entries) {
tabData.entries = [];
}
if (tabData.extData) {
tab.__SS_extdata = {};
for (let key in tabData.extData)
tab.__SS_extdata[key] = tabData.extData[key];
} else {
delete tab.__SS_extdata;
}
browser.__SS_tabStillLoading = true;
// keep the data around to prevent dataloss in case
@ -2562,11 +2574,7 @@ let SessionStoreInternal = {
browser.setAttribute("pending", "true");
tab.setAttribute("pending", "true");
// Make sure that set/getTabValue will set/read the correct data by
// wiping out any current value in tab.__SS_extdata.
delete tab.__SS_extdata;
if (!tabData.entries || tabData.entries.length == 0) {
if (tabData.entries.length == 0) {
// make sure to blank out this tab's content
// (just purging the tab's history won't be enough)
browser.loadURIWithFlags("about:blank",
@ -2601,114 +2609,84 @@ let SessionStoreInternal = {
tab.crop = "center";
}
}
// Restore tab attributes.
if ("attributes" in tabData) {
TabAttributes.set(tab, tabData.attributes);
}
// Restore the tab icon.
if ("image" in tabData) {
tabbrowser.setIcon(tab, tabData.image);
}
}
// helper hashes for ensuring unique frame IDs and unique document
// identifiers.
let idMap = { used: {} };
let docIdentMap = {};
this.restoreHistory(aWindow, aTabs, aTabData, idMap, docIdentMap,
aRestoreImmediately);
function restoreNextHistory() {
if (aWindow.closed) {
return;
}
// if the tab got removed before being completely restored, then skip it
while (aTabs.length > 0 && !this._canRestoreTabHistory(aTabs[0])) {
aTabs.shift();
aTabData.shift();
}
if (aTabs.length == 0) {
// At this point we're essentially ready for consumers to read/write data
// via the sessionstore API so we'll send the SSWindowStateReady event.
this._setWindowStateReady(aWindow);
return; // no more tabs to restore
}
let tab = aTabs.shift();
let tabData = aTabData.shift();
this.restoreHistory(aWindow, tab, tabData, aRestoreImmediately);
// Restore the history in the next tab
aWindow.setTimeout(restoreNextHistory.bind(this), 0);
}
restoreNextHistory.call(this);
},
/**
* Restore history for a list of tabs.
* @param aWindow
* @param window
* Window reference
* @param aTabs
* Array of tab references
* @param aTabData
* Array of tab data
* @param aIdMap
* Hash for ensuring unique frame IDs
* @param aRestoreImmediately
* @param tab
* Tab to be restored
* @param tabData
* Tab data to restore
* @param restoreImmediately
* Flag to indicate whether the given set of tabs aTabs should be
* restored/loaded immediately even if restore_on_demand = true
*/
restoreHistory:
function ssi_restoreHistory(aWindow, aTabs, aTabData, aIdMap, aDocIdentMap,
aRestoreImmediately)
{
// if the tab got removed before being completely restored, then skip it
while (aTabs.length > 0 && !(this._canRestoreTabHistory(aTabs[0]))) {
aTabs.shift();
aTabData.shift();
}
if (aTabs.length == 0) {
// At this point we're essentially ready for consumers to read/write data
// via the sessionstore API so we'll send the SSWindowStateReady event.
this._setWindowStateReady(aWindow);
return; // no more tabs to restore
}
var tab = aTabs.shift();
var tabData = aTabData.shift();
var browser = aWindow.gBrowser.getBrowserForTab(tab);
var history = browser.webNavigation.sessionHistory;
if (history.count > 0) {
history.PurgeHistory(history.count);
}
history.QueryInterface(Ci.nsISHistoryInternal);
restoreHistory: function (window, tab, tabData, restoreImmediately) {
let browser = tab.linkedBrowser;
let history = browser.webNavigation.sessionHistory;
browser.__SS_shistoryListener = new SessionStoreSHistoryListener(tab);
history.addSHistoryListener(browser.__SS_shistoryListener);
if (!tabData.entries) {
tabData.entries = [];
}
if (tabData.extData) {
tab.__SS_extdata = {};
for (let key in tabData.extData)
tab.__SS_extdata[key] = tabData.extData[key];
}
else
delete tab.__SS_extdata;
for (var i = 0; i < tabData.entries.length; i++) {
//XXXzpao Wallpaper patch for bug 514751
if (!tabData.entries[i].url)
continue;
history.addEntry(this._deserializeHistoryEntry(tabData.entries[i],
aIdMap, aDocIdentMap), true);
}
SessionHistory.restore(browser.docShell, tabData);
// make sure to reset the capabilities and attributes, in case this tab gets reused
let disallow = new Set(tabData.disallow && tabData.disallow.split(","));
DocShellCapabilities.restore(browser.docShell, disallow);
// Restore tab attributes.
if ("attributes" in tabData) {
TabAttributes.set(tab, tabData.attributes);
}
// Restore the tab icon.
if ("image" in tabData) {
aWindow.gBrowser.setIcon(tab, tabData.image);
}
if (tabData.storage && browser.docShell instanceof Ci.nsIDocShell)
SessionStorage.deserialize(browser.docShell, tabData.storage);
// notify the tabbrowser that the tab chrome has been restored
var event = aWindow.document.createEvent("Events");
var event = window.document.createEvent("Events");
event.initEvent("SSTabRestoring", true, false);
tab.dispatchEvent(event);
// Restore the history in the next tab
aWindow.setTimeout(() => {
if (!aWindow.closed) {
this.restoreHistory(aWindow, aTabs, aTabData, aIdMap, aDocIdentMap,
aRestoreImmediately);
}
}, 0);
// This could cause us to ignore MAX_CONCURRENT_TAB_RESTORES a bit, but
// it ensures each window will have its selected tab loaded.
if (aRestoreImmediately || aWindow.gBrowser.selectedBrowser == browser) {
this.restoreTab(tab);
}
else {
if (restoreImmediately || window.gBrowser.selectedBrowser == browser) {
this.restoreTabContent(tab);
} else {
TabRestoreQueue.add(tab);
this.restoreNextTab();
}
@ -2731,7 +2709,7 @@ let SessionStoreInternal = {
*
* @returns true/false indicating whether or not a load actually happened
*/
restoreTab: function ssi_restoreTab(aTab) {
restoreTabContent: function (aTab) {
let window = aTab.ownerDocument.defaultView;
let browser = aTab.linkedBrowser;
let tabData = browser.__SS_data;
@ -2834,7 +2812,7 @@ let SessionStoreInternal = {
let tab = TabRestoreQueue.shift();
if (tab) {
let didStartLoad = this.restoreTab(tab);
let didStartLoad = this.restoreTabContent(tab);
// If we don't start a load in the restored tab (eg, no entries) then we
// want to attempt to restore the next tab.
if (!didStartLoad)
@ -2842,136 +2820,6 @@ let SessionStoreInternal = {
}
},
/**
* expands serialized history data into a session-history-entry instance
* @param aEntry
* Object containing serialized history data for a URL
* @param aIdMap
* Hash for ensuring unique frame IDs
* @returns nsISHEntry
*/
_deserializeHistoryEntry:
function ssi_deserializeHistoryEntry(aEntry, aIdMap, aDocIdentMap) {
var shEntry = Cc["@mozilla.org/browser/session-history-entry;1"].
createInstance(Ci.nsISHEntry);
shEntry.setURI(Utils.makeURI(aEntry.url));
shEntry.setTitle(aEntry.title || aEntry.url);
if (aEntry.subframe)
shEntry.setIsSubFrame(aEntry.subframe || false);
shEntry.loadType = Ci.nsIDocShellLoadInfo.loadHistory;
if (aEntry.contentType)
shEntry.contentType = aEntry.contentType;
if (aEntry.referrer)
shEntry.referrerURI = Utils.makeURI(aEntry.referrer);
if (aEntry.isSrcdocEntry)
shEntry.srcdocData = aEntry.srcdocData;
if (aEntry.cacheKey) {
var cacheKey = Cc["@mozilla.org/supports-PRUint32;1"].
createInstance(Ci.nsISupportsPRUint32);
cacheKey.data = aEntry.cacheKey;
shEntry.cacheKey = cacheKey;
}
if (aEntry.ID) {
// get a new unique ID for this frame (since the one from the last
// start might already be in use)
var id = aIdMap[aEntry.ID] || 0;
if (!id) {
for (id = Date.now(); id in aIdMap.used; id++);
aIdMap[aEntry.ID] = id;
aIdMap.used[id] = true;
}
shEntry.ID = id;
}
if (aEntry.docshellID)
shEntry.docshellID = aEntry.docshellID;
if (aEntry.structuredCloneState && aEntry.structuredCloneVersion) {
shEntry.stateData =
Cc["@mozilla.org/docshell/structured-clone-container;1"].
createInstance(Ci.nsIStructuredCloneContainer);
shEntry.stateData.initFromBase64(aEntry.structuredCloneState,
aEntry.structuredCloneVersion);
}
if (aEntry.scroll) {
var scrollPos = (aEntry.scroll || "0,0").split(",");
scrollPos = [parseInt(scrollPos[0]) || 0, parseInt(scrollPos[1]) || 0];
shEntry.setScrollPosition(scrollPos[0], scrollPos[1]);
}
if (aEntry.postdata_b64) {
var postdata = atob(aEntry.postdata_b64);
var stream = Cc["@mozilla.org/io/string-input-stream;1"].
createInstance(Ci.nsIStringInputStream);
stream.setData(postdata, postdata.length);
shEntry.postData = stream;
}
let childDocIdents = {};
if (aEntry.docIdentifier) {
// If we have a serialized document identifier, try to find an SHEntry
// which matches that doc identifier and adopt that SHEntry's
// BFCacheEntry. If we don't find a match, insert shEntry as the match
// for the document identifier.
let matchingEntry = aDocIdentMap[aEntry.docIdentifier];
if (!matchingEntry) {
matchingEntry = {shEntry: shEntry, childDocIdents: childDocIdents};
aDocIdentMap[aEntry.docIdentifier] = matchingEntry;
}
else {
shEntry.adoptBFCacheEntry(matchingEntry.shEntry);
childDocIdents = matchingEntry.childDocIdents;
}
}
if (aEntry.owner_b64) {
var ownerInput = Cc["@mozilla.org/io/string-input-stream;1"].
createInstance(Ci.nsIStringInputStream);
var binaryData = atob(aEntry.owner_b64);
ownerInput.setData(binaryData, binaryData.length);
var binaryStream = Cc["@mozilla.org/binaryinputstream;1"].
createInstance(Ci.nsIObjectInputStream);
binaryStream.setInputStream(ownerInput);
try { // Catch possible deserialization exceptions
shEntry.owner = binaryStream.readObject(true);
} catch (ex) { debug(ex); }
}
if (aEntry.children && shEntry instanceof Ci.nsISHContainer) {
for (var i = 0; i < aEntry.children.length; i++) {
//XXXzpao Wallpaper patch for bug 514751
if (!aEntry.children[i].url)
continue;
// We're getting sessionrestore.js files with a cycle in the
// doc-identifier graph, likely due to bug 698656. (That is, we have
// an entry where doc identifier A is an ancestor of doc identifier B,
// and another entry where doc identifier B is an ancestor of A.)
//
// If we were to respect these doc identifiers, we'd create a cycle in
// the SHEntries themselves, which causes the docshell to loop forever
// when it looks for the root SHEntry.
//
// So as a hack to fix this, we restrict the scope of a doc identifier
// to be a node's siblings and cousins, and pass childDocIdents, not
// aDocIdents, to _deserializeHistoryEntry. That is, we say that two
// SHEntries with the same doc identifier have the same document iff
// they have the same parent or their parents have the same document.
shEntry.AddChild(this._deserializeHistoryEntry(aEntry.children[i], aIdMap,
childDocIdents), i);
}
}
return shEntry;
},
/**
* Accumulates a list of frames that need to be restored for the
* given browser element. A frame is only restored if its current
@ -3508,7 +3356,7 @@ let SessionStoreInternal = {
/**
* Determine if we can restore history into this tab.
* This will be false when a tab has been removed (usually between
* restoreHistoryPrecursor && restoreHistory) or if the tab is still marked
* restoreTabs && restoreHistory) or if the tab is still marked
* as loading.
*
* @param aTab
@ -3835,11 +3683,11 @@ let SessionStoreInternal = {
}
else if (previousState == TAB_STATE_NEEDS_RESTORE) {
// Make sure the session history listener is removed. This is normally
// done in restoreTab, but this tab is being removed before that gets called.
// done in restoreTabContent, but this tab is being removed before that gets called.
this._removeSHistoryListener(aTab);
// Make sure that the tab is removed from the list of tabs to restore.
// Again, this is normally done in restoreTab, but that isn't being called
// Again, this is normally done in restoreTabContent, but that isn't being called
// for this tab.
TabRestoreQueue.remove(aTab);
}
@ -4129,9 +3977,9 @@ SessionStoreSHistoryListener.prototype = {
},
OnHistoryReload: function(aReloadURI, aReloadFlags) {
// On reload, we want to make sure that session history loads the right
// URI. In order to do that, we will juet call restoreTab. That will remove
// URI. In order to do that, we will juet call restoreTabContent. That will remove
// the history listener and load the right URI.
SessionStoreInternal.restoreTab(this.tab);
SessionStoreInternal.restoreTabContent(this.tab);
// Returning false will stop the load that docshell is attempting.
return false;
}

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

@ -404,7 +404,8 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
DebuggerController.SourceScripts.togglePrettyPrint(source)
.then(resetEditor, printError)
.then(DebuggerView.showEditor);
.then(DebuggerView.showEditor)
.then(this.updateToolbarButtonsState);
},
/**

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

@ -128,6 +128,7 @@ skip-if = true
[browser_dbg_pretty-print-09.js]
[browser_dbg_pretty-print-10.js]
[browser_dbg_pretty-print-11.js]
[browser_dbg_pretty-print-12.js]
[browser_dbg_progress-listener-bug.js]
[browser_dbg_reload-preferred-script-01.js]
[browser_dbg_reload-preferred-script-02.js]

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

@ -0,0 +1,54 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure that we don't leave the pretty print button checked when we fail to
* pretty print a source (because it isn't a JS file, for example).
*/
const TAB_URL = EXAMPLE_URL + "doc_blackboxing.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gEditor, gSources;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gEditor = gDebugger.DebuggerView.editor;
gSources = gDebugger.DebuggerView.Sources;
waitForSourceShown(gPanel, "")
.then(() => {
let shown = ensureSourceIs(gPanel, TAB_URL, true)
gSources.selectedValue = TAB_URL;
return shown;
})
.then(clickPrettyPrintButton)
.then(testButtonIsntChecked)
.then(() => closeDebuggerAndFinish(gPanel))
.then(null, aError => {
ok(false, "Got an error: " + DevToolsUtils.safeErrorString(aError));
});
});
}
function clickPrettyPrintButton() {
gDebugger.document.getElementById("pretty-print").click();
}
function testButtonIsntChecked() {
is(gDebugger.document.getElementById("pretty-print").checked, false,
"The button shouldn't be checked after trying to pretty print a non-js file.");
}
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gEditor = null;
gSources = null;
});

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

@ -54,6 +54,10 @@
<checkbox label="&options.enablePersistentLogging.label;"
tooltiptext="&options.enablePersistentLogging.tooltip;"
data-pref="devtools.webconsole.persistlog"/>
<checkbox id="webconsole-timestamp-messages"
label="&options.timestampMessages.label;"
tooltiptext="&options.timestampMessages.tooltip;"
data-pref="devtools.webconsole.timestampMessages"/>
</vbox>
<label value="&options.profiler.label;"/>
<vbox id="profiler-options" class="options-groupbox">

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

@ -239,3 +239,4 @@ skip-if = os == "linux"
[browser_webconsole_view_source.js]
[browser_webconsole_reflow.js]
[browser_webconsole_log_file_filter.js]
[browser_webconsole_expandable_timestamps.js]

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

@ -22,6 +22,13 @@ function testFilterButtons(aHud) {
testMenuFilterButton("css");
testMenuFilterButton("js");
testMenuFilterButton("logging");
testMenuFilterButton("security");
testIsolateFilterButton("net");
testIsolateFilterButton("css");
testIsolateFilterButton("js");
testIsolateFilterButton("logging");
testIsolateFilterButton("security");
finishTest();
}
@ -72,15 +79,7 @@ function testMenuFilterButton(aCategory) {
"checked after turning off its first menu item");
// Turn all the filters off by clicking the main part of the button.
let anonymousNodes = hud.ui.document.getAnonymousNodes(button);
let subbutton;
for (let i = 0; i < anonymousNodes.length; i++) {
let node = anonymousNodes[i];
if (node.classList.contains("toolbarbutton-menubutton-button")) {
subbutton = node;
break;
}
}
let subbutton = getMainButton(button);
ok(subbutton, "we have the subbutton for category " + aCategory);
clickButton(subbutton);
@ -129,10 +128,81 @@ function testMenuFilterButton(aCategory) {
clickButton(subbutton);
}
function testIsolateFilterButton(aCategory) {
let selector = ".webconsole-filter-button[category=\"" + aCategory + "\"]";
let targetButton = hudBox.querySelector(selector);
ok(targetButton, "we have the \"" + aCategory + "\" button");
// Get the main part of the filter button.
let subbutton = getMainButton(targetButton);
ok(subbutton, "we have the subbutton for category " + aCategory);
// Turn on all the filters by alt clicking the main part of the button.
altClickButton(subbutton);
ok(isChecked(targetButton), "the button for category " + aCategory +
" is checked after isolating for filter");
// Check if all the filters for the target button are on.
let menuItems = targetButton.querySelectorAll("menuitem");
Array.forEach(menuItems, (item) => {
let prefKey = item.getAttribute("prefKey");
ok(isChecked(item), "menu item " + prefKey + " for category " +
aCategory + " is checked after isolating for " + aCategory);
ok(hud.ui.filterPrefs[prefKey], prefKey + " messages are " +
"turned on after isolating for " + aCategory);
});
// Ensure all other filter buttons are toggled off and their
// associated filters are turned off
let buttons = hudBox.querySelectorAll(".webconsole-filter-button[category]");
Array.forEach(buttons, (filterButton) => {
if (filterButton !== targetButton) {
let category = filterButton.getAttribute("category");
ok(!isChecked(filterButton), "the button for category " +
category + " is unchecked after isolating for " + aCategory);
menuItems = filterButton.querySelectorAll("menuitem");
Array.forEach(menuItems, (item) => {
let prefKey = item.getAttribute("prefKey");
ok(!isChecked(item), "menu item " + prefKey + " for category " +
aCategory + " is unchecked after isolating for " + aCategory);
ok(!hud.ui.filterPrefs[prefKey], prefKey + " messages are " +
"turned off after isolating for " + aCategory);
});
// Turn all the filters on again by clicking the button.
let mainButton = getMainButton(filterButton);
clickButton(mainButton);
}
});
}
/**
* Return the main part of the target filter button.
*/
function getMainButton(aTargetButton) {
let anonymousNodes = hud.ui.document.getAnonymousNodes(aTargetButton);
let subbutton;
for (let i = 0; i < anonymousNodes.length; i++) {
let node = anonymousNodes[i];
if (node.classList.contains("toolbarbutton-menubutton-button")) {
subbutton = node;
break;
}
}
return subbutton;
}
function clickButton(aNode) {
EventUtils.sendMouseEvent({ type: "click" }, aNode);
}
function altClickButton(aNode) {
EventUtils.sendMouseEvent({ type: "click", altKey: true }, aNode);
}
function chooseMenuItem(aNode) {
let event = document.createEvent("XULCommandEvent");
event.initCommandEvent("command", true, true, window, 0, false, false, false,

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

@ -0,0 +1,57 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Test for the message timestamps option: check if the preference toggles the
// display of messages in the console output. See bug 722267.
function test()
{
const PREF_MESSAGE_TIMESTAMP = "devtools.webconsole.timestampMessages";
let hud;
registerCleanupFunction(() => {
Services.prefs.clearUserPref(PREF_MESSAGE_TIMESTAMP);
});
addTab("data:text/html;charset=utf-8,Web Console test for bug 722267 - " +
"preference for toggling timestamps in messages");
browser.addEventListener("load", function tabLoad() {
browser.removeEventListener("load", tabLoad, true);
openConsole(null, consoleOpened);
}, true);
function consoleOpened(aHud)
{
hud = aHud;
info("console opened");
let prefValue = Services.prefs.getBoolPref(PREF_MESSAGE_TIMESTAMP);
ok(!prefValue, "messages have no timestamp by default (pref check)");
ok(hud.outputNode.classList.contains("hideTimestamps"),
"messages have no timestamp (class name check)");
let toolbox = gDevTools.getToolbox(hud.target);
toolbox.selectTool("options").then(onOptionsPanelSelected);
}
function onOptionsPanelSelected(panel)
{
info("options panel opened");
gDevTools.once("pref-changed", onPrefChanged);
let checkbox = panel.panelDoc.getElementById("webconsole-timestamp-messages");
checkbox.click();
}
function onPrefChanged()
{
info("pref changed");
let prefValue = Services.prefs.getBoolPref(PREF_MESSAGE_TIMESTAMP);
ok(prefValue, "messages have timestamps (pref check)");
ok(!hud.outputNode.classList.contains("hideTimestamps"),
"messages have timestamps (class name check)");
finishTest();
}
}

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

@ -171,6 +171,7 @@ const MAX_LONG_STRING_LENGTH = 200000;
const PREF_CONNECTION_TIMEOUT = "devtools.debugger.remote-timeout";
const PREF_PERSISTLOG = "devtools.webconsole.persistlog";
const PREF_MESSAGE_TIMESTAMP = "devtools.webconsole.timestampMessages";
/**
* A WebConsoleFrame instance is an interactive console initialized *per target*
@ -201,6 +202,7 @@ function WebConsoleFrame(aWebConsoleOwner)
this._toggleFilter = this._toggleFilter.bind(this);
this._onPanelSelected = this._onPanelSelected.bind(this);
this._flushMessageQueue = this._flushMessageQueue.bind(this);
this._onToolboxPrefChanged = this._onToolboxPrefChanged.bind(this);
this._outputTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
this._outputTimerInitialized = false;
@ -571,6 +573,13 @@ WebConsoleFrame.prototype = {
if (toolbox) {
toolbox.on("webconsole-selected", this._onPanelSelected);
}
// Toggle the timestamp on preference change
gDevTools.on("pref-changed", this._onToolboxPrefChanged);
this._onToolboxPrefChanged("pref-changed", {
pref: PREF_MESSAGE_TIMESTAMP,
newValue: Services.prefs.getBoolPref(PREF_MESSAGE_TIMESTAMP),
});
},
/**
@ -801,18 +810,26 @@ WebConsoleFrame.prototype = {
break;
}
// Toggle on the targeted filter button, and if the user alt clicked,
// toggle off all other filter buttons and their associated filters.
let state = target.getAttribute("checked") !== "true";
if (aEvent.getModifierState("Alt")) {
let buttons = this.document
.querySelectorAll(".webconsole-filter-button");
Array.forEach(buttons, (button) => {
if (button !== target) {
button.setAttribute("checked", false);
this._setMenuState(button, false);
}
});
state = true;
}
target.setAttribute("checked", state);
// This is a filter button with a drop-down, and the user clicked the
// main part of the button. Go through all the severities and toggle
// their associated filters.
let menuItems = target.querySelectorAll("menuitem");
for (let i = 0; i < menuItems.length; i++) {
menuItems[i].setAttribute("checked", state);
let prefKey = menuItems[i].getAttribute("prefKey");
this.setFilterState(prefKey, state);
}
this._setMenuState(target, state);
break;
}
@ -851,6 +868,25 @@ WebConsoleFrame.prototype = {
}
},
/**
* Set the menu attributes for a specific toggle button.
*
* @private
* @param XULElement aTarget
* Button with drop down items to be toggled.
* @param boolean aState
* True if the menu item is being toggled on, and false otherwise.
*/
_setMenuState: function WCF__setMenuState(aTarget, aState)
{
let menuItems = aTarget.querySelectorAll("menuitem");
Array.forEach(menuItems, (item) => {
item.setAttribute("checked", aState);
let prefKey = item.getAttribute("prefKey");
this.setFilterState(prefKey, aState);
});
},
/**
* Set the filter state for a specific toggle button.
*
@ -2775,6 +2811,29 @@ WebConsoleFrame.prototype = {
}, false);
},
/**
* Handler for the pref-changed event coming from the toolbox.
* Currently this function only handles the timestamps preferences.
*
* @private
* @param object aEvent
* This parameter is a string that holds the event name
* pref-changed in this case.
* @param object aData
* This is the pref-changed data object.
*/
_onToolboxPrefChanged: function WCF__onToolboxPrefChanged(aEvent, aData)
{
if (aData.pref == PREF_MESSAGE_TIMESTAMP) {
if (aData.newValue) {
this.outputNode.classList.remove("hideTimestamps");
}
else {
this.outputNode.classList.add("hideTimestamps");
}
}
},
/**
* Copies the selected items to the system clipboard.
*
@ -2885,6 +2944,8 @@ WebConsoleFrame.prototype = {
toolbox.off("webconsole-selected", this._onPanelSelected);
}
gDevTools.off("pref-changed", this._onToolboxPrefChanged);
this._repeatNodes = {};
this._outputQueue = [];
this._pruneCategoriesQueue = {};

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

@ -48,8 +48,8 @@ function goUpdateConsoleCommands() {
<command id="cmd_close" oncommand="goDoCommand('cmd_close');" disabled="true"/>
</commandset>
<keyset id="consoleKeys">
<key id="key_fullZoomReduce" key="&fullZoomReduceCmd.commandkey;" command="cmd_fullZoomReduce" modifiers="accel"/>
<key key="&fullZoomReduceCmd.commandkey2;" command="cmd_fullZoomReduce" modifiers="accel"/>
<key id="key_fullZoomReduce" key="&fullZoomReduceCmd.commandkey;" command="cmd_fullZoomReduce" modifiers="accel"/>
<key key="&fullZoomReduceCmd.commandkey2;" command="cmd_fullZoomReduce" modifiers="accel"/>
<key id="key_fullZoomEnlarge" key="&fullZoomEnlargeCmd.commandkey;" command="cmd_fullZoomEnlarge" modifiers="accel"/>
<key key="&fullZoomEnlargeCmd.commandkey2;" command="cmd_fullZoomEnlarge" modifiers="accel"/>
<key key="&fullZoomEnlargeCmd.commandkey3;" command="cmd_fullZoomEnlarge" modifiers="accel"/>

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

@ -109,6 +109,11 @@
<!ENTITY options.enablePersistentLogging.label "Enable persistent logs">
<!ENTITY options.enablePersistentLogging.tooltip "If you enable this option the Web Console will not clear the output each time you navigate to a new page">
<!-- LOCALIZATION NOTE (options.timestampMessages.label): This is the
- label for the checkbox that toggles timestamps in the Web Console -->
<!ENTITY options.timestampMessages.label "Enable timestamps">
<!ENTITY options.timestampMessages.tooltip "If you enable this option commands and output in the Web Console will display a timestamp">
<!-- LOCALIZATION NOTE (options.profiler.label): This is the label for the
- heading of the group of JavaScript Profiler preferences in the options
- panel. -->

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

@ -170,9 +170,8 @@ var ContextCommands = {
// Link specific
openLinkInNewTab: function cc_openLinkInNewTab() {
let tab = Browser.addTab(ContextMenuUI.popupState.linkURL, false, Browser.selectedTab);
ContextUI.peekTabs(kOpenInNewTabAnimationDelayMsec);
Elements.tabList.strip.ensureElementIsVisible(tab.chromeTab);
let url = ContextMenuUI.popupState.linkURL;
BrowserUI.openLinkInNewTab(url, false, Browser.selectedTab);
},
copyLink: function cc_copyLink() {

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

@ -161,7 +161,7 @@ var ContextUI = {
* Dismiss tab bar after a delay. Fires context ui events.
*/
dismissTabsWithDelay: function (aDelay) {
aDelay = aDelay || kNewTabAnimationDelayMsec;
aDelay = aDelay || kForegroundTabAnimationDelay;
this._clearDelayedTimeout();
this._hidingId = setTimeout(function () {
ContextUI.dismissTabs();

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

@ -39,6 +39,9 @@ var APZCObserver = {
handleEvent: function APZC_handleEvent(aEvent) {
switch (aEvent.type) {
case 'pageshow':
if (aEvent.target != Browser.selectedBrowser.contentDocument)
break;
// fall through to TabSelect:
case 'TabSelect':
// ROOT_ID doesn't really identify the view we want. When we call
// this on a content document (tab), findElementWithViewId will

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

@ -66,6 +66,9 @@ XPCOMUtils.defineLazyServiceGetter(window, "gFaviconService",
XPCOMUtils.defineLazyServiceGetter(window, "gFocusManager",
"@mozilla.org/focus-manager;1",
"nsIFocusManager");
XPCOMUtils.defineLazyServiceGetter(window, "gEventListenerService",
"@mozilla.org/eventlistenerservice;1",
"nsIEventListenerService");
#ifdef MOZ_CRASHREPORTER
XPCOMUtils.defineLazyServiceGetter(this, "CrashReporter",
"@mozilla.org/xre/app-info;1",

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

@ -14,12 +14,12 @@ Cu.import("resource://gre/modules/devtools/dbg-server.jsm")
const debugServerStateChanged = "devtools.debugger.remote-enabled";
const debugServerPortChanged = "devtools.debugger.remote-port";
// delay when showing the tab bar briefly after a new (empty) tab opens
const kNewTabAnimationDelayMsec = 1000;
// delay when showing the tab bar after opening a link on a new tab
const kOpenInNewTabAnimationDelayMsec = 3000;
// delay before closing tab bar after selecting another tab
const kSelectTabAnimationDelayMsec = 500;
// delay when showing the tab bar briefly after a new foreground tab opens
const kForegroundTabAnimationDelay = 1000;
// delay when showing the tab bar after opening a new background tab opens
const kBackgroundTabAnimationDelay = 3000;
// delay before closing tab bar after closing or selecting a tab
const kChangeTabAnimationDelay = 500;
/**
* Cache of commonly used elements.
@ -173,6 +173,14 @@ var BrowserUI = {
},
uninit: function() {
messageManager.removeMessageListener("DOMTitleChanged", this);
messageManager.removeMessageListener("DOMWillOpenModalDialog", this);
messageManager.removeMessageListener("DOMWindowClose", this);
messageManager.removeMessageListener("Browser:OpenURI", this);
messageManager.removeMessageListener("Browser:SaveAs:Return", this);
messageManager.removeMessageListener("Content:StateChange", this);
messageManager.removeMessageListener("Browser:MozApplicationManifest", OfflineApps);
Services.obs.removeObserver(this, "handle-xul-text-link");
@ -180,7 +188,6 @@ var BrowserUI = {
FlyoutPanelsUI.uninit();
MetroDownloadsView.uninit();
SettingsCharm.uninit();
messageManager.removeMessageListener("Content:StateChange", this);
PageThumbs.uninit();
this.stopDebugServer();
},
@ -436,10 +443,25 @@ var BrowserUI = {
* See Browser.addTab for more documentation.
*/
addAndShowTab: function (aURI, aOwner) {
ContextUI.peekTabs(kNewTabAnimationDelayMsec);
ContextUI.peekTabs(kForegroundTabAnimationDelay);
return Browser.addTab(aURI || kStartURI, true, aOwner);
},
/**
* Open a new tab in response to clicking a link in an existing tab.
* See Browser.addTab for more documentation.
*/
openLinkInNewTab: function (aURI, aBringFront, aOwner) {
ContextUI.peekTabs(aBringFront ? kForegroundTabAnimationDelay
: kBackgroundTabAnimationDelay);
let tab = Browser.addTab(aURI, aBringFront, aOwner, {
referrerURI: aOwner.browser.documentURI,
charset: aOwner.browser.characterSet,
});
Elements.tabList.strip.ensureElementIsVisible(tab.chromeTab);
return tab;
},
setOnTabAnimationEnd: function setOnTabAnimationEnd(aCallback) {
Elements.tabs.addEventListener("animationend", function onAnimationEnd() {
Elements.tabs.removeEventListener("animationend", onAnimationEnd);
@ -464,7 +486,7 @@ var BrowserUI = {
this.setOnTabAnimationEnd(function() {
Browser.closeTab(tabToClose, { forceClose: true } );
if (wasCollapsed)
ContextUI.dismissTabsWithDelay(kNewTabAnimationDelayMsec);
ContextUI.dismissTabsWithDelay(kChangeTabAnimationDelay);
});
},
@ -506,7 +528,7 @@ var BrowserUI = {
selectTabAndDismiss: function selectTabAndDismiss(aTab) {
this.selectTab(aTab);
ContextUI.dismissTabsWithDelay(kSelectTabAnimationDelayMsec);
ContextUI.dismissTabsWithDelay(kChangeTabAnimationDelay);
},
selectTabAtIndex: function selectTabAtIndex(aIndex) {

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

@ -79,6 +79,7 @@ var Browser = {
// Call InputSourceHelper first so global listeners get called before
// we start processing input in TouchModule.
InputSourceHelper.init();
ClickEventHandler.init();
TouchModule.init();
GestureModule.init();
@ -213,6 +214,7 @@ var Browser = {
shutdown: function shutdown() {
APZCObserver.shutdown();
BrowserUI.uninit();
ClickEventHandler.uninit();
ContentAreaObserver.shutdown();
Appbar.shutdown();
@ -485,7 +487,7 @@ var Browser = {
if (aBringFront)
this.selectedTab = newTab;
this._announceNewTab(newTab, params, aBringFront);
this._announceNewTab(newTab);
return newTab;
},
@ -511,7 +513,7 @@ var Browser = {
* helper for addTab related methods. Fires events related to
* new tab creation.
*/
_announceNewTab: function _announceNewTab(aTab, aParams, aBringFront) {
_announceNewTab: function (aTab) {
let event = document.createEvent("UIEvents");
event.initUIEvent("TabOpen", true, false, window, 0);
aTab.chromeTab.dispatchEvent(event);
@ -1020,9 +1022,6 @@ Browser.MainDragger.prototype = {
};
const OPEN_APPTAB = 100; // Hack until we get a real API
function nsBrowserAccess() { }
nsBrowserAccess.prototype = {
@ -1032,56 +1031,54 @@ nsBrowserAccess.prototype = {
throw Cr.NS_NOINTERFACE;
},
_getOpenAction: function _getOpenAction(aURI, aOpener, aWhere, aContext) {
let where = aWhere;
/*
* aWhere:
* OPEN_DEFAULTWINDOW: default action
* OPEN_CURRENTWINDOW: current window/tab
* OPEN_NEWWINDOW: not allowed, converted to newtab below
* OPEN_NEWTAB: open a new tab
* OPEN_SWITCHTAB: open in an existing tab if it matches, otherwise open
* a new tab. afaict we always open these in the current tab.
*/
if (where == Ci.nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW) {
// query standard browser prefs indicating what to do for default action
switch (aContext) {
// indicates this is an open request from a 3rd party app.
case Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL :
where = Services.prefs.getIntPref("browser.link.open_external");
break;
// internal request
default :
where = Services.prefs.getIntPref("browser.link.open_newwindow");
}
}
if (where == Ci.nsIBrowserDOMWindow.OPEN_NEWWINDOW) {
Util.dumpLn("Invalid request - we can't open links in new windows.");
where = Ci.nsIBrowserDOMWindow.OPEN_NEWTAB;
}
return where;
},
_getBrowser: function _getBrowser(aURI, aOpener, aWhere, aContext) {
let isExternal = (aContext == Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL);
// We don't allow externals apps opening chrome docs
if (isExternal && aURI && aURI.schemeIs("chrome"))
return null;
let location;
let browser;
let loadflags = isExternal ?
Ci.nsIWebNavigation.LOAD_FLAGS_FROM_EXTERNAL :
Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
let location;
if (aWhere == Ci.nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW) {
switch (aContext) {
case Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL :
aWhere = Services.prefs.getIntPref("browser.link.open_external");
break;
default : // OPEN_NEW or an illegal value
aWhere = Services.prefs.getIntPref("browser.link.open_newwindow");
}
}
let openAction = this._getOpenAction(aURI, aOpener, aWhere, aContext);
let browser;
if (aWhere == Ci.nsIBrowserDOMWindow.OPEN_NEWWINDOW) {
let url = aURI ? aURI.spec : "about:blank";
let newWindow = openDialog("chrome://browser/content/browser.xul", "_blank",
"all,dialog=no", url, null, null, null);
// since newWindow.Browser doesn't exist yet, just return null
return null;
} else if (aWhere == Ci.nsIBrowserDOMWindow.OPEN_NEWTAB) {
if (openAction == Ci.nsIBrowserDOMWindow.OPEN_NEWTAB) {
let owner = isExternal ? null : Browser.selectedTab;
let tab = Browser.addTab("about:blank", true, owner);
if (isExternal)
tab.closeOnExit = true;
let tab = BrowserUI.openLinkInNewTab("about:blank", true, owner);
browser = tab.browser;
} else if (aWhere == OPEN_APPTAB) {
Browser.tabs.forEach(function(aTab) {
if ("appURI" in aTab.browser && aTab.browser.appURI.spec == aURI.spec) {
Browser.selectedTab = aTab;
browser = aTab.browser;
}
});
if (!browser) {
// Make a new tab to hold the app
let tab = Browser.addTab("about:blank", true);
browser = tab.browser;
browser.appURI = aURI;
} else {
// Just use the existing browser, but return null to keep the system from trying to load the URI again
browser = null;
}
} else { // OPEN_CURRENTWINDOW and illegal values
} else {
browser = Browser.selectedBrowser;
}
@ -1097,10 +1094,6 @@ nsBrowserAccess.prototype = {
browser.focus();
} catch(e) { }
// We are loading web content into this window, so make sure content is visible
// XXX Can we remove this? It seems to be reproduced in BrowserUI already.
BrowserUI.showContent();
return browser;
},
@ -1584,3 +1577,68 @@ function rendererFactory(aBrowser, aCanvas) {
return wrapper;
};
// Based on ClickEventHandler from /browser/base/content/content.js
let ClickEventHandler = {
init: function () {
gEventListenerService.addSystemEventListener(Elements.browsers, "click", this, true);
},
uninit: function () {
gEventListenerService.removeSystemEventListener(Elements.browsers, "click", this, true);
},
handleEvent: function (aEvent) {
if (!aEvent.isTrusted || aEvent.defaultPrevented) {
return;
}
let [href, node] = this._hrefAndLinkNodeForClickEvent(aEvent);
if (href && (aEvent.button == 1 || aEvent.ctrlKey)) {
// Open link in a new tab for middle-click or ctrl-click
BrowserUI.openLinkInNewTab(href, aEvent.shiftKey, Browser.selectedTab);
}
},
/**
* Extracts linkNode and href for the current click target.
*
* @param event
* The click event.
* @return [href, linkNode].
*
* @note linkNode will be null if the click wasn't on an anchor
* element (or XLink).
*/
_hrefAndLinkNodeForClickEvent: function(event) {
function isHTMLLink(aNode) {
return ((aNode instanceof content.HTMLAnchorElement && aNode.href) ||
(aNode instanceof content.HTMLAreaElement && aNode.href) ||
aNode instanceof content.HTMLLinkElement);
}
let node = event.target;
while (node && !isHTMLLink(node)) {
node = node.parentNode;
}
if (node)
return [node.href, node];
// If there is no linkNode, try simple XLink.
let href, baseURI;
node = event.target;
while (node && !href) {
if (node.nodeType == content.Node.ELEMENT_NODE) {
href = node.getAttributeNS("http://www.w3.org/1999/xlink", "href");
if (href)
baseURI = node.ownerDocument.baseURIObject;
}
node = node.parentNode;
}
// In case of XLink, we don't return the node we got href from since
// callers expect <a>-like elements.
// Note: makeURI() will throw if aUri is not a valid URI.
return [href ? Services.io.newURI(href, null, baseURI).spec : null, null];
}
};

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

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>link click test</title>
</head>
<body>
<a id="link" href="about:blank">link</a>
</body>
</html>

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

@ -0,0 +1,97 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
function test() {
waitForExplicitFinish();
runTests();
}
gTests.push({
desc: "regular link click",
run: function () {
let tab = yield addTab(chromeRoot + "browser_link_click.html");
let tabCount = Browser.tabs.length;
EventUtils.sendMouseEvent({type: "click"}, "link", tab.browser.contentWindow);
yield waitForCondition(() => tab.browser.currentURI.spec == "about:blank");
is(Browser.tabs.length, tabCount, "link loaded in the same tab");
}
});
gTests.push({
desc: "middle-click opens link in background tab",
run: function () {
let tab = yield addTab(chromeRoot + "browser_link_click.html");
let tabOpen = waitForEvent(window, "TabOpen");
EventUtils.sendMouseEvent({type: "click", button: 1}, "link", tab.browser.contentWindow);
let event = yield tabOpen;
let newTab = Browser.getTabFromChrome(event.originalTarget);
yield waitForEvent(newTab.browser, "pageshow");
is(newTab.browser.currentURI.spec, "about:blank");
ok(newTab != Browser.selectedTab, "new tab is in the background");
Browser.closeTab(newTab, { forceClose: true });
}
});
gTests.push({
desc: "shift-middle-click opens link in background tab",
run: function () {
let tab = yield addTab(chromeRoot + "browser_link_click.html");
let tabOpen = waitForEvent(window, "TabOpen");
EventUtils.sendMouseEvent({type: "click", button: 1, shiftKey: true}, "link", tab.browser.contentWindow);
let event = yield tabOpen;
let newTab = Browser.getTabFromChrome(event.originalTarget);
yield waitForEvent(newTab.browser, "pageshow");
is(newTab.browser.currentURI.spec, "about:blank");
ok(newTab == Browser.selectedTab, "new tab is in the foreground");
Browser.closeTab(newTab, { forceClose: true });
}
});
gTests.push({
desc: "ctrl-click opens link in background tab",
run: function () {
let tab = yield addTab(chromeRoot + "browser_link_click.html");
let tabOpen = waitForEvent(window, "TabOpen");
EventUtils.sendMouseEvent({type: "click", ctrlKey: true}, "link", tab.browser.contentWindow);
let event = yield tabOpen;
let newTab = Browser.getTabFromChrome(event.originalTarget);
yield waitForEvent(newTab.browser, "pageshow");
is(newTab.browser.currentURI.spec, "about:blank");
ok(newTab != Browser.selectedTab, "new tab is in the background");
Browser.closeTab(newTab, { forceClose: true });
}
});
gTests.push({
desc: "shift-ctrl-click opens link in background tab",
run: function () {
let tab = yield addTab(chromeRoot + "browser_link_click.html");
let tabOpen = waitForEvent(window, "TabOpen");
EventUtils.sendMouseEvent({type: "click", ctrlKey: true, shiftKey: true}, "link", tab.browser.contentWindow);
let event = yield tabOpen;
let newTab = Browser.getTabFromChrome(event.originalTarget);
yield waitForEvent(newTab.browser, "pageshow");
is(newTab.browser.currentURI.spec, "about:blank");
ok(newTab == Browser.selectedTab, "new tab is in the foreground");
Browser.closeTab(newTab, { forceClose: true });
}
});

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

@ -6,6 +6,7 @@ support-files =
browser_context_menu_tests_04.html
browser_findbar.html
browser_form_auto_complete.html
browser_link_click.html
browser_onscreen_keyboard.html
browser_progress_indicator.xul
browser_selection_basic.html
@ -42,6 +43,7 @@ support-files =
[browser_form_auto_complete.js]
[browser_history.js]
[browser_inputsource.js]
[browser_link_click.js]
[browser_onscreen_keyboard.js]
[browser_prefs_ui.js]
[browser_remotetabs.js]

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

@ -112,6 +112,10 @@ a {
align-items: flex-start;
}
#output-container.hideTimestamps > .message > .timestamp {
display: none;
}
.filtered-by-type,
.filtered-by-string {
display: none;

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

@ -5,6 +5,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
XPIDL_SOURCES += [
'nsIDomainPolicy.idl',
'nsIPrincipal.idl',
'nsIScriptSecurityManager.idl',
'nsISecurityCheckedComponent.idl',

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

@ -0,0 +1,62 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#include "nsISupports.idl"
interface nsIURI;
interface nsIDomainSet;
/*
* When a domain policy is instantiated by invoking activateDomainPolicy() on
* nsIScriptSecurityManager, these domain sets are consulted when each new
* global is created (they have no effect on already-created globals).
* If javascript is globally enabled with |javascript.enabled|, the blacklists
* are consulted. If globally disabled, the whitelists are consulted. Lookups
* on blacklist and whitelist happen with contains(), and lookups on
* superBlacklist and superWhitelist happen with containsSuperDomain().
*
* When deactivate() is invoked, the domain sets are emptied, and the
* nsIDomainPolicy ceases to have any effect on the system.
*/
[scriptable, builtinclass, uuid(27b10f54-f34b-42b7-8594-4348d3ad7953)]
interface nsIDomainPolicy : nsISupports
{
readonly attribute nsIDomainSet blacklist;
readonly attribute nsIDomainSet superBlacklist;
readonly attribute nsIDomainSet whitelist;
readonly attribute nsIDomainSet superWhitelist;
void deactivate();
};
[scriptable, builtinclass, uuid(946a01ff-6525-4007-a2c2-447ebe1875d3)]
interface nsIDomainSet : nsISupports
{
/*
* Add a domain to the set. No-op if it already exists.
*/
void add(in nsIURI aDomain);
/*
* Remove a domain from the set. No-op if it doesn't exist.
*/
void remove(in nsIURI aDomain);
/*
* Remove all entries from the set.
*/
void clear();
/*
* Returns true if a given domain is in the set.
*/
bool contains(in nsIURI aDomain);
/*
* Returns true if a given domain is a subdomain of one of the entries in
* the set.
*/
bool containsSuperDomain(in nsIURI aDomain);
};

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

@ -9,8 +9,9 @@
interface nsIURI;
interface nsIChannel;
interface nsIDocShell;
interface nsIDomainPolicy;
[scriptable, uuid(d6475e53-9ece-4dc0-940c-095ac3d85363)]
[scriptable, uuid(2911ae60-1b5f-47e6-941e-1bb7b53a167d)]
interface nsIScriptSecurityManager : nsIXPCSecurityManager
{
///////////////// Security Checks //////////////////
@ -103,24 +104,9 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager
in unsigned long flags);
/**
* Check that the function 'funObj' is allowed to run on 'targetObj'
*
* Will return error code NS_ERROR_DOM_SECURITY_ERR if the function
* should not run
*
* @param cx The current active JavaScript context.
* @param funObj The function trying to run..
* @param targetObj The object the function will run on.
* Return true if scripts may be executed in the scope of the given global.
*/
[noscript] void checkFunctionAccess(in JSContextPtr cx, in voidPtr funObj,
in voidPtr targetObj);
/**
* Return true if content from the given principal is allowed to
* execute scripts.
*/
[noscript] boolean canExecuteScripts(in JSContextPtr cx,
in nsIPrincipal principal);
[noscript,notxpcom] boolean scriptAllowed(in JSObjectPtr aGlobal);
///////////////// Principals ///////////////////////
/**
@ -216,6 +202,13 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager
* script to check whether a given principal is system.
*/
boolean isSystemPrincipal(in nsIPrincipal aPrincipal);
%{C++
bool IsSystemPrincipal(nsIPrincipal* aPrincipal) {
bool isSystem = false;
IsSystemPrincipal(aPrincipal, &isSystem);
return isSystem;
}
%}
/**
* Same as getSubjectPrincipal(), only faster. cx must *never* be
@ -236,6 +229,29 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager
* inMozBrowser has to be true if the app is inside a mozbrowser iframe.
*/
AUTF8String getJarPrefix(in unsigned long appId, in boolean inMozBrowser);
/**
* Per-domain controls to enable and disable script. This system is designed
* to be used by at most one consumer, and enforces this with its semantics.
*
* Initially, domainPolicyActive is false. When activateDomainPolicy() is
* invoked, domainPolicyActive becomes true, and subsequent calls to
* activateDomainPolicy() will fail until deactivate() is invoked on the
* nsIDomainPolicy returned from activateDomainPolicy(). At this point,
* domainPolicyActive becomes false again, and a new consumer may acquire
* control of the system by invoking activateDomainPolicy().
*/
nsIDomainPolicy activateDomainPolicy();
readonly attribute boolean domainPolicyActive;
/**
* Query mechanism for the above policy.
*
* If domainPolicyEnabled is false, this simply returns the current value
* of javascript.enabled. Otherwise, it returns the same value, but taking
* the various blacklist/whitelist exceptions into account.
*/
bool policyAllowsScript(in nsIURI aDomain);
};
%{C++

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

@ -0,0 +1,52 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=8 sts=4 et sw=4 tw=80: */
/* 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/. */
#ifndef DomainPolicy_h__
#define DomainPolicy_h__
#include "nsIDomainPolicy.h"
#include "nsTHashtable.h"
#include "nsURIHashKey.h"
namespace mozilla {
// The name "DomainPolicy" conflicts with some of the old-style policy machinery
// in nsScriptSecurityManager.cpp, which needs to #include this file. So we
// temporarily use a sub-namespace until that machinery goes away in bug 913734.
namespace hotness {
class DomainPolicy : public nsIDomainPolicy
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMAINPOLICY
DomainPolicy();
virtual ~DomainPolicy();
private:
nsCOMPtr<nsIDomainSet> mBlacklist;
nsCOMPtr<nsIDomainSet> mSuperBlacklist;
nsCOMPtr<nsIDomainSet> mWhitelist;
nsCOMPtr<nsIDomainSet> mSuperWhitelist;
};
class DomainSet : public nsIDomainSet
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMAINSET
DomainSet() {}
virtual ~DomainSet() {}
protected:
nsTHashtable<nsURIHashKey> mHashTable;
};
} /* namespace hotness */
} /* namespace mozilla */
#endif /* DomainPolicy_h__ */

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

@ -362,6 +362,8 @@ public:
AppAttributesEqual(nsIPrincipal* aFirst,
nsIPrincipal* aSecond);
void DeactivateDomainPolicy();
private:
// GetScriptSecurityManager is the only call that can make one
@ -381,7 +383,7 @@ private:
// Returns null if a principal cannot be found; generally callers
// should error out at that point.
static nsIPrincipal* doGetObjectPrincipal(JS::Handle<JSObject*> obj);
static nsIPrincipal* doGetObjectPrincipal(JSObject* obj);
// Returns null if a principal cannot be found. Note that rv can be NS_OK
// when this happens -- this means that there was no JS running.
@ -462,15 +464,6 @@ private:
nsIPrincipal* aSubjectPrincipal,
const char* aObjectSecurityLevel);
/**
* Helper for CanExecuteScripts that allows the caller to specify
* whether execution should be allowed if cx has no
* nsIScriptContext.
*/
nsresult
CanExecuteScripts(JSContext* cx, nsIPrincipal *aPrincipal,
bool aAllowIfNoScriptContext, bool *result);
nsresult
Init();
@ -496,6 +489,10 @@ private:
bool mIsJavaScriptEnabled;
bool mPolicyPrefsChanged;
// This machinery controls new-style domain policies. The old-style
// policy machinery will be removed soon.
nsCOMPtr<nsIDomainPolicy> mDomainPolicy;
static bool sStrictFileOriginPolicy;
static nsIIOService *sIOService;

165
caps/src/DomainPolicy.cpp Normal file
Просмотреть файл

@ -0,0 +1,165 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=4 et sw=4 tw=80: */
/* 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/. */
#include "DomainPolicy.h"
#include "nsScriptSecurityManager.h"
namespace mozilla {
namespace hotness {
NS_IMPL_ISUPPORTS1(DomainPolicy, nsIDomainPolicy)
DomainPolicy::DomainPolicy() : mBlacklist(new DomainSet())
, mSuperBlacklist(new DomainSet())
, mWhitelist(new DomainSet())
, mSuperWhitelist(new DomainSet())
{}
DomainPolicy::~DomainPolicy()
{
// The SSM holds a strong ref to the DomainPolicy until Deactivate() is
// invoked, so we should never hit the destructor until that happens.
MOZ_ASSERT(!mBlacklist && !mSuperBlacklist &&
!mWhitelist && !mSuperWhitelist);
}
NS_IMETHODIMP
DomainPolicy::GetBlacklist(nsIDomainSet** aSet)
{
nsCOMPtr<nsIDomainSet> set = mBlacklist;
set.forget(aSet);
return NS_OK;
}
NS_IMETHODIMP
DomainPolicy::GetSuperBlacklist(nsIDomainSet** aSet)
{
nsCOMPtr<nsIDomainSet> set = mSuperBlacklist;
set.forget(aSet);
return NS_OK;
}
NS_IMETHODIMP
DomainPolicy::GetWhitelist(nsIDomainSet** aSet)
{
nsCOMPtr<nsIDomainSet> set = mWhitelist;
set.forget(aSet);
return NS_OK;
}
NS_IMETHODIMP
DomainPolicy::GetSuperWhitelist(nsIDomainSet** aSet)
{
nsCOMPtr<nsIDomainSet> set = mSuperWhitelist;
set.forget(aSet);
return NS_OK;
}
NS_IMETHODIMP
DomainPolicy::Deactivate()
{
// Clear the hashtables first to free up memory, since script might
// hold the doomed sets alive indefinitely.
mBlacklist->Clear();
mSuperBlacklist->Clear();
mWhitelist->Clear();
mSuperWhitelist->Clear();
// Null them out.
mBlacklist = nullptr;
mSuperBlacklist = nullptr;
mWhitelist = nullptr;
mSuperWhitelist = nullptr;
// Inform the SSM.
nsScriptSecurityManager::GetScriptSecurityManager()->DeactivateDomainPolicy();
return NS_OK;
}
static already_AddRefed<nsIURI>
GetCanonicalClone(nsIURI* aURI)
{
nsCOMPtr<nsIURI> clone;
nsresult rv = aURI->Clone(getter_AddRefs(clone));
NS_ENSURE_SUCCESS(rv, nullptr);
rv = clone->SetUserPass(EmptyCString());
NS_ENSURE_SUCCESS(rv, nullptr);
rv = clone->SetPath(EmptyCString());
NS_ENSURE_SUCCESS(rv, nullptr);
return clone.forget();
}
NS_IMPL_ISUPPORTS1(DomainSet, nsIDomainSet)
NS_IMETHODIMP
DomainSet::Add(nsIURI* aDomain)
{
nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain);
NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE);
mHashTable.PutEntry(clone);
return NS_OK;
}
NS_IMETHODIMP
DomainSet::Remove(nsIURI* aDomain)
{
nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain);
NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE);
mHashTable.RemoveEntry(clone);
return NS_OK;
}
NS_IMETHODIMP
DomainSet::Clear()
{
mHashTable.Clear();
return NS_OK;
}
NS_IMETHODIMP
DomainSet::Contains(nsIURI* aDomain, bool* aContains)
{
*aContains = false;
nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain);
NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE);
*aContains = mHashTable.Contains(clone);
return NS_OK;
}
NS_IMETHODIMP
DomainSet::ContainsSuperDomain(nsIURI* aDomain, bool* aContains)
{
*aContains = false;
nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain);
NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE);
nsAutoCString domain;
nsresult rv = clone->GetHost(domain);
NS_ENSURE_SUCCESS(rv, rv);
while (true) {
// Check the current domain.
if (mHashTable.Contains(clone)) {
*aContains = true;
return NS_OK;
}
// Chop off everything before the first dot, or break if there are no
// dots left.
int32_t index = domain.Find(".");
if (index == kNotFound)
break;
domain.Assign(Substring(domain, index + 1));
rv = clone->SetHost(domain);
NS_ENSURE_SUCCESS(rv, rv);
}
// No match.
return NS_OK;
}
} /* namespace hotness */
} /* namespace mozilla */

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

@ -7,6 +7,7 @@
MODULE = 'caps'
SOURCES += [
'DomainPolicy.cpp',
'nsJSPrincipals.cpp',
'nsNullPrincipal.cpp',
'nsNullPrincipalURI.cpp',

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

@ -21,6 +21,7 @@
#include "nsSystemPrincipal.h"
#include "nsPrincipal.h"
#include "nsNullPrincipal.h"
#include "DomainPolicy.h"
#include "nsXPIDLString.h"
#include "nsCRT.h"
#include "nsCRTGlue.h"
@ -63,6 +64,7 @@
#include "mozilla/StaticPtr.h"
#include "nsContentUtils.h"
#include "nsCxPusher.h"
#include "nsJSUtils.h"
// This should be probably defined on some other place... but I couldn't find it
#define WEBAPPS_PERM_NAME "webapps-manage"
@ -183,12 +185,6 @@ GetPrincipalDomainOrigin(nsIPrincipal* aPrincipal,
return GetOriginFromURI(uri, aOrigin);
}
static nsIScriptContext *
GetScriptContext(JSContext *cx)
{
return GetScriptContextFromJSContext(cx);
}
inline void SetPendingException(JSContext *cx, const char *aMsg)
{
JS_ReportError(cx, "%s", aMsg);
@ -1601,173 +1597,38 @@ nsScriptSecurityManager::CheckLoadURIStrWithPrincipal(nsIPrincipal* aPrincipal,
return rv;
}
NS_IMETHODIMP
nsScriptSecurityManager::CheckFunctionAccess(JSContext *aCx, void *aFunObj,
void *aTargetObj)
bool
nsScriptSecurityManager::ScriptAllowed(JSObject *aGlobal)
{
// This check is called for event handlers
nsresult rv;
JS::Rooted<JSObject*> rootedFunObj(aCx, static_cast<JSObject*>(aFunObj));
nsIPrincipal* subject = doGetObjectPrincipal(rootedFunObj);
if (!subject)
return NS_ERROR_FAILURE;
MOZ_ASSERT(aGlobal);
MOZ_ASSERT(JS_IsGlobalObject(aGlobal) || js::IsOuterObject(aGlobal));
AutoJSContext cx;
JS::RootedObject global(cx, js::UncheckedUnwrap(aGlobal, /* stopAtOuter = */ false));
if (subject == mSystemPrincipal)
// This is the system principal: just allow access
return NS_OK;
// Check if the principal the function was compiled under is
// allowed to execute scripts.
bool result;
rv = CanExecuteScripts(aCx, subject, true, &result);
if (NS_FAILED(rv))
return rv;
if (!result)
return NS_ERROR_DOM_SECURITY_ERR;
if (!aTargetObj) {
// We're done here
return NS_OK;
// Check the bits on the compartment private.
xpc::Scriptability& scriptability = xpc::Scriptability::Get(aGlobal);
if (!scriptability.Allowed()) {
return false;
}
/*
** Get origin of subject and object and compare.
*/
JS::Rooted<JSObject*> obj(aCx, (JSObject*)aTargetObj);
nsIPrincipal* object = doGetObjectPrincipal(obj);
if (!object)
return NS_ERROR_FAILURE;
bool subsumes;
rv = subject->Subsumes(object, &subsumes);
if (NS_SUCCEEDED(rv) && !subsumes) {
rv = NS_ERROR_DOM_PROP_ACCESS_DENIED;
}
return rv;
}
NS_IMETHODIMP
nsScriptSecurityManager::CanExecuteScripts(JSContext* cx,
nsIPrincipal *aPrincipal,
bool *result)
{
return CanExecuteScripts(cx, aPrincipal, false, result);
}
nsresult
nsScriptSecurityManager::CanExecuteScripts(JSContext* cx,
nsIPrincipal *aPrincipal,
bool aAllowIfNoScriptContext,
bool *result)
{
*result = false;
if (aPrincipal == mSystemPrincipal)
{
// Even if JavaScript is disabled, we must still execute system scripts
*result = true;
return NS_OK;
// If the compartment is immune to script policy, we're done.
if (scriptability.IsImmuneToScriptPolicy()) {
return true;
}
// Same thing for nsExpandedPrincipal, which is pseudo-privileged.
nsCOMPtr<nsIExpandedPrincipal> ep = do_QueryInterface(aPrincipal);
if (ep)
{
*result = true;
return NS_OK;
}
//-- See if the current window allows JS execution
nsIScriptContext *scriptContext = GetScriptContext(cx);
if (!scriptContext) {
if (aAllowIfNoScriptContext) {
*result = true;
return NS_OK;
}
return NS_ERROR_FAILURE;
}
if (!scriptContext->GetScriptsEnabled()) {
// No scripting on this context, folks
*result = false;
return NS_OK;
}
nsIScriptGlobalObject *sgo = scriptContext->GetGlobalObject();
if (!sgo) {
return NS_ERROR_FAILURE;
}
// window can be null here if we're running with a non-DOM window
// as the script global (i.e. a XUL prototype document).
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(sgo);
nsCOMPtr<nsIDocShell> docshell;
nsresult rv;
if (window) {
docshell = window->GetDocShell();
}
if (docshell) {
rv = docshell->GetCanExecuteScripts(result);
if (NS_FAILED(rv)) return rv;
if (!*result) return NS_OK;
}
// OK, the docshell doesn't have script execution explicitly disabled.
// Check whether our URI is an "about:" URI that allows scripts. If it is,
// we need to allow JS to run. In this case, don't apply the JS enabled
// pref or policies. On failures, just press on and don't do this special
// case.
nsCOMPtr<nsIURI> principalURI;
aPrincipal->GetURI(getter_AddRefs(principalURI));
if (!principalURI) {
// Broken principal of some sort. Disallow.
*result = false;
return NS_ERROR_UNEXPECTED;
}
bool isAbout;
rv = principalURI->SchemeIs("about", &isAbout);
if (NS_SUCCEEDED(rv) && isAbout) {
nsCOMPtr<nsIAboutModule> module;
rv = NS_GetAboutModule(principalURI, getter_AddRefs(module));
if (NS_SUCCEEDED(rv)) {
uint32_t flags;
rv = module->GetURIFlags(principalURI, &flags);
if (NS_SUCCEEDED(rv) &&
(flags & nsIAboutModule::ALLOW_SCRIPT)) {
*result = true;
return NS_OK;
}
}
}
*result = mIsJavaScriptEnabled;
if (!*result)
return NS_OK; // Do not run scripts
//-- Check for a per-site policy
// Check for a per-site policy.
static const char jsPrefGroupName[] = "javascript";
ClassInfoData nameData(nullptr, jsPrefGroupName);
SecurityLevel secLevel;
rv = LookupPolicy(aPrincipal, nameData, EnabledID(),
nsIXPCSecurityManager::ACCESS_GET_PROPERTY,
nullptr, &secLevel);
if (NS_FAILED(rv) || secLevel.level == SCRIPT_SECURITY_NO_ACCESS)
{
*result = false;
return rv;
nsresult rv = LookupPolicy(doGetObjectPrincipal(global), nameData,
EnabledID(),
nsIXPCSecurityManager::ACCESS_GET_PROPERTY,
nullptr, &secLevel);
if (NS_FAILED(rv) || secLevel.level == SCRIPT_SECURITY_NO_ACCESS) {
return false;
}
//-- Nobody vetoed, so allow the JS to run.
*result = true;
return NS_OK;
return true;
}
///////////////// Principals ///////////////////////
@ -1964,7 +1825,7 @@ nsScriptSecurityManager::GetObjectPrincipal(JSContext *aCx, JSObject *aObj,
// static
nsIPrincipal*
nsScriptSecurityManager::doGetObjectPrincipal(JS::Handle<JSObject*> aObj)
nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj)
{
JSCompartment *compartment = js::GetObjectCompartment(aObj);
JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment);
@ -2291,6 +2152,9 @@ nsScriptSecurityManager::~nsScriptSecurityManager(void)
if(mDefaultPolicy)
mDefaultPolicy->Drop();
delete mCapabilities;
if (mDomainPolicy)
mDomainPolicy->Deactivate();
MOZ_ASSERT(!mDomainPolicy);
}
void
@ -2716,3 +2580,74 @@ nsScriptSecurityManager::GetJarPrefix(uint32_t aAppId,
mozilla::GetJarPrefix(aAppId, aInMozBrowser, aJarPrefix);
return NS_OK;
}
NS_IMETHODIMP
nsScriptSecurityManager::GetDomainPolicyActive(bool *aRv)
{
*aRv = !!mDomainPolicy;
return NS_OK;
}
NS_IMETHODIMP
nsScriptSecurityManager::ActivateDomainPolicy(nsIDomainPolicy** aRv)
{
// We only allow one domain policy at a time. The holder of the previous
// policy must explicitly deactivate it first.
if (mDomainPolicy) {
return NS_ERROR_SERVICE_NOT_AVAILABLE;
}
mDomainPolicy = new mozilla::hotness::DomainPolicy();
nsCOMPtr<nsIDomainPolicy> ptr = mDomainPolicy;
ptr.forget(aRv);
return NS_OK;
}
// Intentionally non-scriptable. Script must have a reference to the
// nsIDomainPolicy to deactivate it.
void
nsScriptSecurityManager::DeactivateDomainPolicy()
{
mDomainPolicy = nullptr;
}
NS_IMETHODIMP
nsScriptSecurityManager::PolicyAllowsScript(nsIURI* aURI, bool *aRv)
{
nsresult rv;
// Compute our rule. If we don't have any domain policy set up that might
// provide exceptions to this rule, we're done.
*aRv = mIsJavaScriptEnabled;
if (!mDomainPolicy) {
return NS_OK;
}
// We have a domain policy. Grab the appropriate set of exceptions to the
// rule (either the blacklist or the whitelist, depending on whether script
// is enabled or disabled by default).
nsCOMPtr<nsIDomainSet> exceptions;
nsCOMPtr<nsIDomainSet> superExceptions;
if (*aRv) {
mDomainPolicy->GetBlacklist(getter_AddRefs(exceptions));
mDomainPolicy->GetSuperBlacklist(getter_AddRefs(superExceptions));
} else {
mDomainPolicy->GetWhitelist(getter_AddRefs(exceptions));
mDomainPolicy->GetSuperWhitelist(getter_AddRefs(superExceptions));
}
bool contains;
rv = exceptions->Contains(aURI, &contains);
NS_ENSURE_SUCCESS(rv, rv);
if (contains) {
*aRv = !*aRv;
return NS_OK;
}
rv = superExceptions->ContainsSuperDomain(aURI, &contains);
NS_ENSURE_SUCCESS(rv, rv);
if (contains) {
*aRv = !*aRv;
}
return NS_OK;
}

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

@ -1,10 +0,0 @@
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# jarPrefix test doesn't work on Windows, see bug 776296.
ifneq ($(OS_ARCH),WINNT)
MOCHITEST_CHROME_FILES = test_principal_jarprefix_origin_appid_appstatus.html \
$(NULL)
endif

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

@ -0,0 +1,4 @@
[test_disableScript.xul]
[test_principal_jarprefix_origin_appid_appstatus.html]
# jarPrefix test doesn't work on Windows, see bug 776296.
skip-if = os == "win"

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

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<script>
var gFiredOnload = false;
var gFiredOnclick = false;
</script>
</head>
<body onload="gFiredOnload = true;" onclick="gFiredOnclick = true;">
</body>
</html>

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

@ -1,4 +1,6 @@
[DEFAULT]
support-files =
file_disableScript.html
[test_app_principal_equality.html]
[test_bug246699.html]

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

@ -5,4 +5,5 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
MOCHITEST_MANIFESTS += ['mochitest.ini']
MOCHITEST_CHROME_MANIFESTS += ['chrome.ini']

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

@ -0,0 +1,321 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=840488
-->
<window title="Mozilla Bug 840488"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=840488"
target="_blank">Mozilla Bug 840488</a>
</body>
<iframe id="root" name="root" onload="go();" type="content"/>
<!-- test code goes here -->
<script type="application/javascript">
<![CDATA[
/** Test for all the different ways that script can be disabled for a given global. **/
SimpleTest.waitForExplicitFinish();
const Cu = Components.utils;
const Ci = Components.interfaces;
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/Services.jsm");
const ssm = Services.scriptSecurityManager;
function makeURI(uri) { return Services.io.newURI(uri, null, null); }
const path = "/tests/caps/tests/mochitest/file_disableScript.html";
const uri = "http://www.example.com" + path;
var rootFrame = document.getElementById('root');
rootFrame.setAttribute('src', uri + "?name=rootframe");
function navigateFrame(ifr, src) {
let deferred = Promise.defer();
function onload() {
ifr.removeEventListener('load', onload);
deferred.resolve();
}
ifr.addEventListener('load', onload, false);
ifr.setAttribute('src', src);
return deferred.promise;
}
function navigateBack(ifr) {
let deferred = Promise.defer();
// pageshow events don't fire on the iframe element, so we need to use the
// chrome event handler for the docshell.
var browser = ifr.contentWindow
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell)
.chromeEventHandler;
function onpageshow(evt) {
info("Navigated back. Persisted: " + evt.persisted);
browser.removeEventListener('pageshow', onpageshow);
deferred.resolve();
}
browser.addEventListener('pageshow', onpageshow, false);
ifr.contentWindow.history.back();
return deferred.promise;
}
function addFrame(parentWin, name, expectOnload) {
let ifr = parentWin.document.createElement('iframe');
parentWin.document.body.appendChild(ifr);
ifr.setAttribute('name', name);
let deferred = Promise.defer();
// We need to append 'name' to avoid running afoul of recursive frame detection.
let frameURI = uri + "?name=" + name;
navigateFrame(ifr, frameURI).then(function() {
is(ifr.contentWindow.location, frameURI, "Successful load");
is(!!ifr.contentWindow.wrappedJSObject.gFiredOnload, expectOnload,
"onload should only fire when scripts are enabled");
deferred.resolve();
});
return deferred.promise;
}
function checkScriptEnabled(win, expectEnabled) {
win.wrappedJSObject.gFiredOnclick = false;
win.document.body.dispatchEvent(new win.Event('click'));
is(win.wrappedJSObject.gFiredOnclick, expectEnabled, "Checking script-enabled for " + win.name + " (" + win.location + ")");
}
function setScriptEnabledForDocShell(win, enabled) {
win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell)
.allowJavascript = enabled;
}
function testList(expectEnabled, win, list, idx) {
let idx = idx || 0;
let deferred = Promise.defer();
let target = list[idx] + path;
info("Testing scriptability for: " + target + ". expecting " + expectEnabled);
navigateFrame(win.frameElement, target).then(function() {
checkScriptEnabled(win, expectEnabled);
if (idx == list.length - 1)
deferred.resolve();
else
testList(expectEnabled, win, list, idx + 1).then(function() { deferred.resolve(); });
});
return deferred.promise;
}
function testDomainPolicy(defaultScriptability, exceptions, superExceptions,
exempt, notExempt, set, superSet, win) {
// Populate our sets.
for (var e of exceptions)
set.add(makeURI(e));
for (var e of superExceptions)
superSet.add(makeURI(e));
return testList(defaultScriptability, win, notExempt).then(function() {
return testList(!defaultScriptability, win, exempt);
});
}
function setScriptEnabledForBrowser(enabled) {
var prefname = "javascript.enabled";
Services.prefs.setBoolPref(prefname, enabled);
}
function reloadFrame(frame) {
let deferred = Promise.defer();
frame.addEventListener('load', function onload() {
deferred.resolve();
frame.removeEventListener('load', onload);
}, false);
frame.contentWindow.location.reload(true);
return deferred.promise;
}
function go() {
rootFrame.setAttribute('onload', null);
// Test simple docshell enable/disable.
var rootWin = rootFrame.contentWindow;
checkScriptEnabled(rootWin, true);
setScriptEnabledForDocShell(rootWin, false);
checkScriptEnabled(rootWin, false);
setScriptEnabledForDocShell(rootWin, true);
checkScriptEnabled(rootWin, true);
// Play around with the docshell tree and make sure everything works as
// we expect.
addFrame(rootWin, 'parent', true).then(function() {
checkScriptEnabled(rootWin[0], true);
return addFrame(rootWin[0], 'childA', true);
}).then(function() {
checkScriptEnabled(rootWin[0][0], true);
setScriptEnabledForDocShell(rootWin[0], false);
checkScriptEnabled(rootWin, true);
checkScriptEnabled(rootWin[0], false);
checkScriptEnabled(rootWin[0][0], false);
return addFrame(rootWin[0], 'childB', false);
}).then(function() {
checkScriptEnabled(rootWin[0][1], false);
setScriptEnabledForDocShell(rootWin[0][0], false);
setScriptEnabledForDocShell(rootWin[0], true);
checkScriptEnabled(rootWin[0], true);
checkScriptEnabled(rootWin[0][0], false);
setScriptEnabledForDocShell(rootWin[0][0], true);
// Flags are inherited from the parent docshell at attach time. Note that
// the flag itself is inherited, regardless of whether or not scripts are
// currently allowed on the parent (which could depend on the parent's
// parent). Check that.
checkScriptEnabled(rootWin[0][1], false);
setScriptEnabledForDocShell(rootWin[0], false);
setScriptEnabledForDocShell(rootWin[0][1], true);
return addFrame(rootWin[0][1], 'grandchild', false);
}).then(function() {
checkScriptEnabled(rootWin[0], false);
checkScriptEnabled(rootWin[0][1], false);
checkScriptEnabled(rootWin[0][1][0], false);
setScriptEnabledForDocShell(rootWin[0], true);
checkScriptEnabled(rootWin[0], true);
checkScriptEnabled(rootWin[0][1], true);
checkScriptEnabled(rootWin[0][1][0], true);
// Try navigating two frames, then munging docshell scriptability, then
// pulling the frames out of the bfcache to make sure that flags are
// properly propagated to inactive inner windows. We do this both for an
// 'own' docshell, as well as for an ancestor docshell.
return navigateFrame(rootWin[0][0].frameElement, rootWin[0][0].location + '-navigated');
}).then(function() { return navigateFrame(rootWin[0][1][0].frameElement, rootWin[0][1][0].location + '-navigated'); })
.then(function() {
checkScriptEnabled(rootWin[0][0], true);
checkScriptEnabled(rootWin[0][1][0], true);
setScriptEnabledForDocShell(rootWin[0][0], false);
setScriptEnabledForDocShell(rootWin[0][1], false);
checkScriptEnabled(rootWin[0][0], false);
checkScriptEnabled(rootWin[0][1][0], false);
return navigateBack(rootWin[0][0].frameElement);
}).then(function() { return navigateBack(rootWin[0][1][0].frameElement); })
.then(function() {
checkScriptEnabled(rootWin[0][0], false);
checkScriptEnabled(rootWin[0][1][0], false);
// Disable JS via the global pref pref. This is only guaranteed to have an effect
// for subsequent loads.
setScriptEnabledForBrowser(false);
return reloadFrame(rootFrame);
}).then(function() {
checkScriptEnabled(rootWin, false);
setScriptEnabledForBrowser(true);
return reloadFrame(rootFrame);
}).then(function() {
checkScriptEnabled(rootWin, true);
// Play around with dynamically blocking script for a given global.
// This takes effect immediately.
Cu.blockScriptForGlobal(rootWin);
Cu.blockScriptForGlobal(rootWin);
Cu.unblockScriptForGlobal(rootWin);
checkScriptEnabled(rootWin, false);
Cu.unblockScriptForGlobal(rootWin);
checkScriptEnabled(rootWin, true);
Cu.blockScriptForGlobal(rootWin);
return reloadFrame(rootFrame);
}).then(function() {
checkScriptEnabled(rootWin, true);
// Test system-wide domain policy. This only takes effect for subsequently-
// loaded globals.
// Check the basic semantics of the sets.
is(ssm.domainPolicyActive, false, "not enabled");
window.policy = ssm.activateDomainPolicy();
ok(policy instanceof Ci.nsIDomainPolicy, "Got a policy");
try {
ssm.activateDomainPolicy();
ok(false, "Should have thrown");
} catch (e) {
ok(true, "can't have two live domain policies");
}
var sbRef = policy.superBlacklist;
isnot(sbRef, null, "superBlacklist non-null");
ok(!sbRef.contains(makeURI('http://www.example.com')));
sbRef.add(makeURI('http://www.example.com/foopy'));
ok(sbRef.contains(makeURI('http://www.example.com')));
sbRef.remove(makeURI('http://www.example.com'));
ok(!sbRef.contains(makeURI('http://www.example.com')));
sbRef.add(makeURI('http://www.example.com/foopy/this.that/'));
ok(sbRef.contains(makeURI('http://www.example.com/baz')));
ok(!sbRef.contains(makeURI('https://www.example.com')));
ok(!sbRef.contains(makeURI('https://www.example.com:88')));
ok(!sbRef.contains(makeURI('http://foo.www.example.com')));
ok(sbRef.containsSuperDomain(makeURI('http://foo.www.example.com')));
ok(sbRef.containsSuperDomain(makeURI('http://foo.bar.www.example.com')));
ok(!sbRef.containsSuperDomain(makeURI('http://foo.bar.www.exxample.com')));
ok(!sbRef.containsSuperDomain(makeURI('http://example.com')));
ok(!sbRef.containsSuperDomain(makeURI('http://com/this.that/')));
ok(!sbRef.containsSuperDomain(makeURI('https://foo.www.example.com')));
ok(sbRef.contains(makeURI('http://www.example.com')));
policy.deactivate();
is(ssm.domainPolicyActive, false, "back to inactive");
ok(!sbRef.contains(makeURI('http://www.example.com')),
"Disabling domain policy clears the set");
policy = ssm.activateDomainPolicy();
ok(policy.superBlacklist);
isnot(sbRef, policy.superBlacklist, "Mint new sets each time!");
policy.deactivate();
is(policy.blacklist, null, "blacklist nulled out");
policy = ssm.activateDomainPolicy();
isnot(policy.blacklist, null, "non-null again");
isnot(policy.blacklist, sbRef, "freshly minted");
policy.deactivate();
//
// Now, create and apply a mock-policy. We check the same policy both as
// a blacklist and as a whitelist.
//
window.testPolicy = {
// The policy.
exceptions: ['http://test1.example.com', 'http://example.com'],
superExceptions: ['http://test2.example.org', 'https://test1.example.com'],
// The testcases.
exempt: ['http://test1.example.com', 'http://example.com',
'http://test2.example.org', 'http://sub1.test2.example.org',
'https://sub1.test1.example.com'],
notExempt: ['http://test2.example.com', 'http://sub1.test1.example.com',
'http://www.example.com', 'https://test2.example.com',
'https://example.com', 'http://test1.example.org'],
};
policy = ssm.activateDomainPolicy();
info("Testing Blacklist-style Domain Policy");
return testDomainPolicy(true, testPolicy.exceptions,
testPolicy.superExceptions, testPolicy.exempt,
testPolicy.notExempt, policy.blacklist,
policy.superBlacklist, rootWin);
}).then(function() {
policy.deactivate();
policy = ssm.activateDomainPolicy();
info("Testing Whitelist-style Domain Policy");
setScriptEnabledForBrowser(false);
return testDomainPolicy(false, testPolicy.exceptions,
testPolicy.superExceptions, testPolicy.exempt,
testPolicy.notExempt, policy.whitelist,
policy.superWhitelist, rootWin);
}).then(function() {
setScriptEnabledForBrowser(true);
policy.deactivate();
SimpleTest.finish();
});
}
]]>
</script>
</window>

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

@ -223,6 +223,7 @@ if test -n "$gonkdir" ; then
GONK_INCLUDES="-I$gonkdir/frameworks/base/opengl/include -I$gonkdir/frameworks/base/native/include -I$gonkdir/frameworks/base/include -I$gonkdir/frameworks/base/services/camera -I$gonkdir/frameworks/base/include/media/stagefright -I$gonkdir/frameworks/base/include/media/stagefright/openmax -I$gonkdir/frameworks/base/media/libstagefright/rtsp -I$gonkdir/frameworks/base/media/libstagefright/include -I$gonkdir/external/dbus -I$gonkdir/external/bluetooth/bluez/lib -I$gonkdir/dalvik/libnativehelper/include/nativehelper"
MOZ_B2G_BT=1
MOZ_B2G_BT_BLUEZ=1
MOZ_NFC=1
MOZ_B2G_CAMERA=1
MOZ_OMX_DECODER=1
AC_SUBST(MOZ_OMX_DECODER)
@ -239,6 +240,7 @@ if test -n "$gonkdir" ; then
MOZ_B2G_BT_BLUEDROID=1
fi
MOZ_NFC=1
MOZ_B2G_CAMERA=1
MOZ_OMX_DECODER=1
AC_SUBST(MOZ_OMX_DECODER)
@ -7306,6 +7308,18 @@ AC_SUBST(MOZ_B2G_BT)
AC_SUBST(MOZ_B2G_BT_BLUEZ)
AC_SUBST(MOZ_B2G_BT_BLUEDROID)
dnl ========================================================
dnl = Enable NFC Interface for B2G (Gonk usually)
dnl ========================================================
MOZ_ARG_ENABLE_BOOL(b2g-nfc,
[ --enable-nfc Set compile flags necessary for compiling NFC API ],
MOZ_NFC=1,
MOZ_NFC= )
if test -n "$MOZ_NFC"; then
AC_DEFINE(MOZ_NFC)
fi
AC_SUBST(MOZ_NFC)
dnl ========================================================
dnl = Enable Pico Speech Synthesis (Gonk usually)
dnl ========================================================

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

@ -10,10 +10,10 @@
#include "nsAttrAndChildArray.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/MemoryReporting.h"
#include "nsMappedAttributeElement.h"
#include "prbit.h"
#include "nsString.h"
#include "nsHTMLStyleSheet.h"
#include "nsRuleWalker.h"
@ -772,7 +772,7 @@ nsAttrAndChildArray::GrowBy(uint32_t aGrowSize)
} while (size < minSize);
}
else {
size = 1u << PR_CeilingLog2(minSize);
size = 1u << mozilla::CeilingLog2(minSize);
}
bool needToInitialize = !mImpl;

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

@ -253,8 +253,14 @@ public:
// nsWrapperCache
using nsWrapperCache::GetWrapperPreserveColor;
virtual JSObject* WrapObject(JSContext *cx,
JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
protected:
virtual JSObject* GetWrapperPreserveColorInternal() MOZ_OVERRIDE
{
return nsWrapperCache::GetWrapperPreserveColor();
}
public:
// nsIDOMHTMLCollection
NS_DECL_NSIDOMHTMLCOLLECTION

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

@ -7206,19 +7206,10 @@ nsDocument::IsScriptEnabled()
nsCOMPtr<nsIScriptSecurityManager> sm(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID));
NS_ENSURE_TRUE(sm, false);
nsCOMPtr<nsIScriptGlobalObject> globalObject = do_QueryInterface(GetWindow());
NS_ENSURE_TRUE(globalObject, false);
nsCOMPtr<nsIScriptGlobalObject> globalObject = do_QueryInterface(GetInnerWindow());
NS_ENSURE_TRUE(globalObject && globalObject->GetGlobalJSObject(), false);
nsIScriptContext *scriptContext = globalObject->GetContext();
NS_ENSURE_TRUE(scriptContext, false);
AutoPushJSContext cx(scriptContext->GetNativeContext());
NS_ENSURE_TRUE(cx, false);
bool enabled;
nsresult rv = sm->CanExecuteScripts(cx, NodePrincipal(), &enabled);
NS_ENSURE_SUCCESS(rv, false);
return enabled;
return sm->ScriptAllowed(globalObject->GetGlobalJSObject());
}
nsRadioGroupStruct*

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

@ -498,28 +498,6 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
return false;
}
// Script evaluation can also be disabled in the current script
// context even though it's enabled in the document.
// XXX - still hard-coded for JS here, even though another language
// may be specified. Should this check be made *after* we examine
// the attributes to locate the script-type?
// For now though, if JS is disabled we assume every language is
// disabled.
// XXX is this different from the mDocument->IsScriptEnabled() call?
nsCOMPtr<nsIScriptGlobalObject> globalObject =
do_QueryInterface(mDocument->GetWindow());
if (!globalObject) {
return false;
}
nsIScriptContext *context = globalObject->GetScriptContext();
// If scripts aren't enabled in the current context, there's no
// point in going on.
if (!context || !context->GetScriptsEnabled()) {
return false;
}
JSVersion version = JSVERSION_DEFAULT;
// Check the type attribute to determine language and version.

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

@ -1084,9 +1084,9 @@ CanvasRenderingContext2D::GetInputStream(const char *aMimeType,
const PRUnichar *aEncoderOptions,
nsIInputStream **aStream)
{
uint8_t* imageBuffer = nullptr;
nsAutoArrayPtr<uint8_t> imageBuffer;
int32_t format = 0;
GetImageBuffer(&imageBuffer, &format);
GetImageBuffer(getter_Transfers(imageBuffer), &format);
if (!imageBuffer) {
return NS_ERROR_FAILURE;
}

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

@ -794,9 +794,9 @@ WebGLContext::GetInputStream(const char* aMimeType,
if (!gl)
return NS_ERROR_FAILURE;
uint8_t* imageBuffer = nullptr;
nsAutoArrayPtr<uint8_t> imageBuffer;
int32_t format = 0;
GetImageBuffer(&imageBuffer, &format);
GetImageBuffer(getter_Transfers(imageBuffer), &format);
if (!imageBuffer) {
return NS_ERROR_FAILURE;
}

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

@ -24,8 +24,8 @@ class Element;
// IID for the nsIHTMLCollection interface
#define NS_IHTMLCOLLECTION_IID \
{ 0x5643235d, 0x9a72, 0x4b6a, \
{ 0xa6, 0x0c, 0x64, 0x63, 0x72, 0xb7, 0x53, 0x4a } }
{ 0x4e169191, 0x5196, 0x4e17, \
{ 0xa4, 0x79, 0xd5, 0x35, 0x0b, 0x5b, 0x0a, 0xcd } }
/**
* An internal interface
@ -76,11 +76,11 @@ public:
JSObject* GetWrapperPreserveColor()
{
nsWrapperCache* cache;
CallQueryInterface(this, &cache);
return cache->GetWrapperPreserveColor();
return GetWrapperPreserveColorInternal();
}
virtual JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> scope) = 0;
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) = 0;
protected:
virtual JSObject* GetWrapperPreserveColorInternal() = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIHTMLCollection, NS_IHTMLCOLLECTION_IID)

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

@ -79,8 +79,15 @@ public:
nsresult GetSortedControls(nsTArray<nsGenericHTMLFormElement*>& aControls) const;
// nsWrapperCache
virtual JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
using nsWrapperCache::GetWrapperPreserveColor;
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
protected:
virtual JSObject* GetWrapperPreserveColorInternal() MOZ_OVERRIDE
{
return nsWrapperCache::GetWrapperPreserveColor();
}
public:
static bool ShouldBeInElements(nsIFormControl* aFormControl);

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

@ -42,8 +42,14 @@ public:
// nsWrapperCache
using nsWrapperCache::GetWrapperPreserveColor;
virtual JSObject* WrapObject(JSContext* cx,
JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
protected:
virtual JSObject* GetWrapperPreserveColorInternal() MOZ_OVERRIDE
{
return nsWrapperCache::GetWrapperPreserveColor();
}
public:
// nsIDOMHTMLOptionsCollection interface
NS_DECL_NSIDOMHTMLOPTIONSCOLLECTION

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

@ -55,9 +55,16 @@ public:
HTMLPropertiesCollection(nsGenericHTMLElement* aRoot);
virtual ~HTMLPropertiesCollection();
// nsWrapperCache
using nsWrapperCache::GetWrapperPreserveColor;
virtual JSObject* WrapObject(JSContext *cx,
JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
protected:
virtual JSObject* GetWrapperPreserveColorInternal() MOZ_OVERRIDE
{
return nsWrapperCache::GetWrapperPreserveColor();
}
public:
virtual Element* GetElementAt(uint32_t aIndex);

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

@ -50,13 +50,15 @@ public:
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TableRowsCollection)
// nsWrapperCache
virtual JSObject* WrapObject(JSContext *cx,
JS::Handle<JSObject*> scope) MOZ_OVERRIDE
using nsWrapperCache::GetWrapperPreserveColor;
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
protected:
virtual JSObject* GetWrapperPreserveColorInternal() MOZ_OVERRIDE
{
return mozilla::dom::HTMLCollectionBinding::Wrap(cx, scope, this);
return nsWrapperCache::GetWrapperPreserveColor();
}
protected:
// Those rows that are not in table sections
HTMLTableElement* mParent;
nsRefPtr<nsContentList> mOrphanRows;
@ -82,6 +84,13 @@ TableRowsCollection::~TableRowsCollection()
// reference for us.
}
JSObject*
TableRowsCollection::WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aScope)
{
return HTMLCollectionBinding::Wrap(aCx, aScope, this);
}
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(TableRowsCollection, mOrphanRows)
NS_IMPL_CYCLE_COLLECTING_ADDREF(TableRowsCollection)
NS_IMPL_CYCLE_COLLECTING_RELEASE(TableRowsCollection)

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

@ -706,24 +706,17 @@ IsScriptEnabled(nsIDocument *aDoc, nsIDocShell *aContainer)
NS_ENSURE_TRUE(aDoc && aContainer, true);
nsCOMPtr<nsIScriptGlobalObject> globalObject =
do_QueryInterface(aDoc->GetWindow());
do_QueryInterface(aDoc->GetInnerWindow());
// Getting context is tricky if the document hasn't had its
// GlobalObject set yet
if (!globalObject) {
globalObject = aContainer->GetScriptGlobalObject();
NS_ENSURE_TRUE(globalObject, true);
}
nsIScriptContext *scriptContext = globalObject->GetContext();
NS_ENSURE_TRUE(scriptContext, true);
JSContext *cx = scriptContext->GetNativeContext();
NS_ENSURE_TRUE(cx, true);
bool enabled = true;
nsContentUtils::GetSecurityManager()->
CanExecuteScripts(cx, aDoc->NodePrincipal(), &enabled);
return enabled;
NS_ENSURE_TRUE(globalObject && globalObject->GetGlobalJSObject(), true);
return nsContentUtils::GetSecurityManager()->
ScriptAllowed(globalObject->GetGlobalJSObject());
}
nsresult

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

@ -1080,24 +1080,12 @@ nsXBLBinding::AllowScripts()
return false;
}
nsCOMPtr<nsIScriptGlobalObject> global = do_QueryInterface(doc->GetWindow());
if (!global) {
nsCOMPtr<nsIScriptGlobalObject> global = do_QueryInterface(doc->GetInnerWindow());
if (!global || !global->GetGlobalJSObject()) {
return false;
}
nsCOMPtr<nsIScriptContext> context = global->GetContext();
if (!context) {
return false;
}
AutoPushJSContext cx(context->GetNativeContext());
nsCOMPtr<nsIDocument> ourDocument =
mPrototypeBinding->XBLDocumentInfo()->GetDocument();
bool canExecute;
nsresult rv =
mgr->CanExecuteScripts(cx, ourDocument->NodePrincipal(), &canExecute);
return NS_SUCCEEDED(rv) && canExecute;
return mgr->ScriptAllowed(global->GetGlobalJSObject());
}
nsXBLBinding*

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

@ -328,12 +328,12 @@ nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement)
// Now call the method
// Check whether it's OK to call the method.
rv = nsContentUtils::GetSecurityManager()->CheckFunctionAccess(cx, method,
thisObject);
// Check whether script is enabled.
bool scriptAllowed = nsContentUtils::GetSecurityManager()->
ScriptAllowed(js::GetGlobalForObjectCrossCompartment(method));
bool ok = true;
if (NS_SUCCEEDED(rv)) {
if (scriptAllowed) {
JS::Rooted<JS::Value> retval(cx);
ok = ::JS_CallFunctionValue(cx, thisObject, OBJECT_TO_JSVAL(method),
0 /* argc */, nullptr /* argv */, retval.address());

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

@ -3660,18 +3660,14 @@ XULDocument::ExecuteScript(nsIScriptContext * aContext,
NS_ENSURE_TRUE(mScriptGlobalObject, NS_ERROR_NOT_INITIALIZED);
if (!aContext->GetScriptsEnabled())
return NS_OK;
// Execute the precompiled script with the given version
nsAutoMicroTask mt;
JSContext *cx = aContext->GetNativeContext();
AutoCxPusher pusher(cx);
JS::Rooted<JSObject*> global(cx, mScriptGlobalObject->GetGlobalJSObject());
// XXXkhuey can this ever be null?
if (global) {
JS::ExposeObjectToActiveJS(global);
}
NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
NS_ENSURE_TRUE(nsContentUtils::GetSecurityManager()->ScriptAllowed(global), NS_OK);
JS::ExposeObjectToActiveJS(global);
xpc_UnmarkGrayScript(aScriptObject);
JSAutoCompartment ac(cx, global);
JS::Rooted<JS::Value> unused(cx);

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

@ -762,6 +762,7 @@ nsDocShell::nsDocShell():
mUseGlobalHistory(false),
mInPrivateBrowsing(false),
mDeviceSizeIsPageSize(false),
mCanExecuteScripts(false),
mFiredUnloadEvent(false),
mEODForCurrentDocument(false),
mURIResultedInDocument(false),
@ -2077,12 +2078,6 @@ nsDocShell::GetAllowJavascript(bool * aAllowJavascript)
NS_ENSURE_ARG_POINTER(aAllowJavascript);
*aAllowJavascript = mAllowJavascript;
if (!mAllowJavascript) {
return NS_OK;
}
bool unsafe;
*aAllowJavascript = NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe)) && !unsafe;
return NS_OK;
}
@ -2090,6 +2085,7 @@ NS_IMETHODIMP
nsDocShell::SetAllowJavascript(bool aAllowJavascript)
{
mAllowJavascript = aAllowJavascript;
RecomputeCanExecuteScripts();
return NS_OK;
}
@ -2823,6 +2819,48 @@ nsDocShell::GetParentDocshell()
return docshell.forget().downcast<nsDocShell>();
}
void
nsDocShell::RecomputeCanExecuteScripts()
{
bool old = mCanExecuteScripts;
nsRefPtr<nsDocShell> parent = GetParentDocshell();
// If we have no tree owner, that means that we've been detached from the
// docshell tree (this is distinct from having no parent dochshell, which
// is the case for root docshells). In that case, don't allow script.
if (!mTreeOwner) {
mCanExecuteScripts = false;
// If scripting has been explicitly disabled on our docshell, we're done.
} else if (!mAllowJavascript) {
mCanExecuteScripts = false;
// If we have a parent, inherit.
} else if (parent) {
mCanExecuteScripts = parent->mCanExecuteScripts;
// Otherwise, we're the root of the tree, and we haven't explicitly disabled
// script. Allow.
} else {
mCanExecuteScripts = true;
}
// Inform our active DOM window.
//
// This will pass the outer, which will be in the scope of the active inner.
if (mScriptGlobal && mScriptGlobal->GetGlobalJSObject()) {
xpc::Scriptability& scriptability =
xpc::Scriptability::Get(mScriptGlobal->GetGlobalJSObject());
scriptability.SetDocShellAllowsScript(mCanExecuteScripts);
}
// If our value has changed, our children might be affected. Recompute their
// value as well.
if (old != mCanExecuteScripts) {
nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
while (iter.HasMore()) {
static_cast<nsDocShell*>(iter.GetNext())->RecomputeCanExecuteScripts();
}
}
}
nsresult
nsDocShell::SetDocLoaderParent(nsDocLoader * aParent)
{
@ -2892,6 +2930,10 @@ nsDocShell::SetDocLoaderParent(nsDocLoader * aParent)
nsCOMPtr<nsIURIContentListener> parentURIListener(do_GetInterface(parent));
if (parentURIListener)
mContentListener->SetParentContentListener(parentURIListener);
// Our parent has changed. Recompute scriptability.
RecomputeCanExecuteScripts();
return NS_OK;
}
@ -3446,6 +3488,16 @@ nsDocShell::SetTreeOwner(nsIDocShellTreeOwner * aTreeOwner)
child->SetTreeOwner(aTreeOwner);
}
// Our tree owner has changed. Recompute scriptability.
//
// Note that this is near-redundant with the recomputation in
// SetDocLoaderParent(), but not so for the root DocShell, where the call to
// SetTreeOwner() happens after the initial AddDocLoaderAsChildOfRoot(),
// and we never set another parent. Given that this is neither expensive nor
// performance-critical, let's be safe and unconditionally recompute this
// state whenever dependent state changes.
RecomputeCanExecuteScripts();
return NS_OK;
}
@ -12657,20 +12709,7 @@ unsigned long nsDocShell::gNumberOfDocShells = 0;
NS_IMETHODIMP
nsDocShell::GetCanExecuteScripts(bool *aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
*aResult = false; // disallow by default
nsRefPtr<nsDocShell> docshell = this;
do {
nsresult rv = docshell->GetAllowJavascript(aResult);
if (NS_FAILED(rv)) return rv;
if (!*aResult) {
return NS_OK;
}
docshell = docshell->GetParentDocshell();
} while (docshell);
*aResult = mCanExecuteScripts;
return NS_OK;
}

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

@ -813,6 +813,12 @@ protected:
bool mInPrivateBrowsing;
bool mDeviceSizeIsPageSize;
// Because scriptability depends on the mAllowJavascript values of our
// ancestors, we cache the effective scriptability and recompute it when
// it might have changed;
bool mCanExecuteScripts;
void RecomputeCanExecuteScripts();
// This boolean is set to true right before we fire pagehide and generally
// unset when we embed a new content viewer. While it's true no navigation
// is allowed in this docshell.

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

@ -570,7 +570,7 @@ interface nsIDocShell : nsIDocShellTreeItem
* The rule of thumb here is that we disable js if this docshell or any
* of its parents disallow scripting.
*/
readonly attribute boolean canExecuteScripts;
[infallible] readonly attribute boolean canExecuteScripts;
/**
* Sets whether a docshell is active. An active docshell is one that is

Двоичные данные
docshell/test/bug369814.zip

Двоичный файл не отображается.

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

@ -302,6 +302,17 @@ this.PermissionsTable = { geolocation: {
privileged: PROMPT_ACTION,
certified: PROMPT_ACTION
},
"nfc": {
app: DENY_ACTION,
privileged: DENY_ACTION,
certified: ALLOW_ACTION,
access: ["read", "write"]
},
"nfc-manager": {
app: DENY_ACTION,
privileged: DENY_ACTION,
certified: ALLOW_ACTION
},
};
/**

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

@ -1793,6 +1793,18 @@ Navigator::HasFMRadioSupport(JSContext* /* unused */, JSObject* aGlobal)
}
#endif // MOZ_B2G_FM
#ifdef MOZ_NFC
/* static */
bool
Navigator::HasNfcSupport(JSContext* /* unused */, JSObject* aGlobal)
{
nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
return win && (CheckPermission(win, "nfc-read") ||
CheckPermission(win, "nfc-write"));
}
#endif // MOZ_NFC
#ifdef MOZ_TIME_MANAGER
/* static */
bool

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

@ -287,6 +287,9 @@ public:
#ifdef MOZ_B2G_FM
static bool HasFMRadioSupport(JSContext* /* unused */, JSObject* aGlobal);
#endif // MOZ_B2G_FM
#ifdef MOZ_NFC
static bool HasNfcSupport(JSContext* /* unused */, JSObject* aGlobal);
#endif // MOZ_NFC
#ifdef MOZ_TIME_MANAGER
static bool HasTimeSupport(JSContext* /* unused */, JSObject* aGlobal);
#endif // MOZ_TIME_MANAGER

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

@ -139,6 +139,7 @@
#endif
#include "nsIDOMCustomEvent.h"
#include "nsIFrameRequestCallback.h"
#include "nsIJARChannel.h"
#include "xpcprivate.h"
@ -2061,6 +2062,9 @@ WindowStateHolder::WindowStateHolder(nsGlobalWindow *aWindow,
mInnerWindowHolder = aHolder;
aWindow->SuspendTimeouts();
// When a global goes into the bfcache, we disable script.
xpc::Scriptability::Get(aWindow->mJSObject).SetDocShellAllowsScript(false);
}
WindowStateHolder::~WindowStateHolder()
@ -2459,6 +2463,10 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
// Enter the new global's compartment.
JSAutoCompartment ac(cx, mJSObject);
// Set scriptability based on the state of the docshell.
bool allow = GetDocShell()->GetCanExecuteScripts();
xpc::Scriptability::Get(mJSObject).SetDocShellAllowsScript(allow);
// If we created a new inner window above, we need to do the last little bit
// of initialization now that the dust has settled.
if (createdInnerWindow) {
@ -2541,6 +2549,14 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
NS_ENSURE_SUCCESS(rv, rv);
}
// If the document comes from a JAR, check if the channel was determined
// to be unsafe. If so, permanently disable script on the compartment by
// calling Block() and throwing away the key.
nsCOMPtr<nsIJARChannel> jarChannel = do_QueryInterface(aDocument->GetChannel());
if (jarChannel && jarChannel->GetIsUnsafe()) {
xpc::Scriptability::Get(newInnerWindow->mJSObject).Block();
}
if (mArguments) {
newInnerWindow->DefineArgumentsProperty(mArguments);
mArguments = nullptr;
@ -3174,19 +3190,6 @@ nsGlobalWindow::PoisonOuterWindowProxy(JSObject *aObject)
}
}
void
nsGlobalWindow::SetScriptsEnabled(bool aEnabled, bool aFireTimeouts)
{
FORWARD_TO_INNER_VOID(SetScriptsEnabled, (aEnabled, aFireTimeouts));
if (aEnabled && aFireTimeouts) {
// Scripts are enabled (again?) on this context, run timeouts that
// fired on this context while scripts were disabled.
void (nsGlobalWindow::*run)() = &nsGlobalWindow::RunTimeout;
NS_DispatchToCurrentThread(NS_NewRunnableMethod(this, run));
}
}
nsresult
nsGlobalWindow::SetArguments(nsIArray *aArguments)
{
@ -8942,11 +8945,14 @@ NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsGlobalWindow)
NS_IMETHODIMP
nsGlobalWindow::DispatchEvent(nsIDOMEvent* aEvent, bool* aRetVal)
{
MOZ_ASSERT(!IsInnerWindow() || IsCurrentInnerWindow(),
"We should only fire events on the current inner window.");
FORWARD_TO_INNER(DispatchEvent, (aEvent, aRetVal), NS_OK);
if (!IsCurrentInnerWindow()) {
NS_WARNING("DispatchEvent called on non-current inner window, dropping. "
"Please check the window in the caller instead.");
return NS_ERROR_FAILURE;
}
if (!mDoc) {
return NS_ERROR_FAILURE;
}
@ -11824,20 +11830,6 @@ nsGlobalWindow::RunTimeout(nsTimeout *aTimeout)
continue;
}
// The "scripts disabled" concept is still a little vague wrt
// multiple languages. Prepare for the day when languages can be
// disabled independently of the other languages...
if (!scx->GetScriptsEnabled()) {
// Scripts were enabled once in this window (unless aTimeout ==
// nullptr) but now scripts are disabled (we might be in
// print-preview, for instance), this means we shouldn't run any
// timeouts at this point.
//
// If scripts are enabled for this language in this window again
// we'll fire the timeouts that are due at that point.
continue;
}
// This timeout is good to run
++timeoutsRan;
bool timeout_was_cleared = RunTimeoutHandler(timeout, scx);

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

@ -354,7 +354,6 @@ public:
void PoisonOuterWindowProxy(JSObject *aObject);
virtual void OnFinalize(JSObject* aObject);
virtual void SetScriptsEnabled(bool aEnabled, bool aFireTimeouts);
virtual bool IsBlackForCC();

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

@ -27,8 +27,8 @@ class nsIDOMWindow;
class nsIURI;
#define NS_ISCRIPTCONTEXT_IID \
{ 0xf3859ce7, 0x7551, 0x4760, \
{ 0x84, 0x29, 0x64, 0x4f, 0x26, 0x1e, 0xdb, 0x91 } }
{ 0x513c2c1a, 0xf4f1, 0x44da, \
{ 0x8e, 0x38, 0xf4, 0x0c, 0x30, 0x9a, 0x5d, 0xef } }
/* This MUST match JSVERSION_DEFAULT. This version stuff if we don't
know what language we have is a little silly... */
@ -128,12 +128,6 @@ public:
*/
virtual void GC(JS::gcreason::Reason aReason) = 0;
/**
* Called to disable/enable script execution in this context.
*/
virtual bool GetScriptsEnabled() = 0;
virtual void SetScriptsEnabled(bool aEnabled, bool aFireTimeouts) = 0;
// SetProperty is suspect and jst believes should not be needed. Currenly
// used only for "arguments".
virtual nsresult SetProperty(JS::Handle<JSObject*> aTarget,

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

@ -27,8 +27,8 @@ NS_HandleScriptError(nsIScriptGlobalObject *aScriptGlobal,
#define NS_ISCRIPTGLOBALOBJECT_IID \
{ 0x214fa2f6, 0xcc0c, 0x42cf, \
{ 0x98, 0x4b, 0x45, 0xf5, 0x73, 0x9c, 0x6b, 0x73 } }
{ 0xa6c0bfae, 0x8be4, 0x4747, \
{ 0xaf, 0x1a, 0xe3, 0xf0, 0x3f, 0xb6, 0x0e, 0xb8 } }
/**
* The global object which keeps a script context for each supported script
@ -70,11 +70,6 @@ public:
*/
virtual void OnFinalize(JSObject* aObject) = 0;
/**
* Called to enable/disable scripts.
*/
virtual void SetScriptsEnabled(bool aEnabled, bool aFireTimeouts) = 0;
/**
* Handle a script error. Generally called by a script context.
*/

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

@ -839,7 +839,6 @@ nsJSContext::nsJSContext(bool aGCOnDestruction,
js_options_dot_str, this);
}
mIsInitialized = false;
mScriptsEnabled = true;
mProcessingScriptTag = false;
HoldJSObjects(this);
}
@ -950,10 +949,6 @@ nsJSContext::EvaluateString(const nsAString& aScript,
void **aOffThreadToken)
{
NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
if (!mScriptsEnabled) {
return NS_OK;
}
AutoCxPusher pusher(mContext);
nsJSUtils::EvaluateOptions evalOptions;
evalOptions.setCoerceToString(aCoerceToString);
@ -1863,27 +1858,6 @@ nsJSContext::IsContextInitialized()
return mIsInitialized;
}
bool
nsJSContext::GetScriptsEnabled()
{
return mScriptsEnabled;
}
void
nsJSContext::SetScriptsEnabled(bool aEnabled, bool aFireTimeouts)
{
// eeek - this seems the wrong way around - the global should callback
// into each context, so every language is disabled.
mScriptsEnabled = aEnabled;
nsIScriptGlobalObject *global = GetGlobalObject();
if (global) {
global->SetScriptsEnabled(aEnabled, aFireTimeouts);
}
}
bool
nsJSContext::GetProcessingScriptTag()
{

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

@ -59,9 +59,6 @@ public:
virtual nsresult InitContext() MOZ_OVERRIDE;
virtual bool IsContextInitialized() MOZ_OVERRIDE;
virtual bool GetScriptsEnabled() MOZ_OVERRIDE;
virtual void SetScriptsEnabled(bool aEnabled, bool aFireTimeouts) MOZ_OVERRIDE;
virtual nsresult SetProperty(JS::Handle<JSObject*> aTarget, const char* aPropName, nsISupports* aVal) MOZ_OVERRIDE;
virtual bool GetProcessingScriptTag() MOZ_OVERRIDE;
@ -166,7 +163,6 @@ private:
JS::Heap<JSObject*> mWindowProxy;
bool mIsInitialized;
bool mScriptsEnabled;
bool mGCOnDestruction;
bool mProcessingScriptTag;

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

@ -241,15 +241,14 @@ nsJSUtils::EvaluateString(JSContext* aCx,
JS::ExposeObjectToActiveJS(aScopeObject);
nsAutoMicroTask mt;
nsresult rv = NS_OK;
JSPrincipals* p = JS_GetCompartmentPrincipals(js::GetObjectCompartment(aScopeObject));
aCompileOptions.setPrincipals(p);
bool ok = false;
nsresult rv = nsContentUtils::GetSecurityManager()->
CanExecuteScripts(aCx, nsJSPrincipals::get(p), &ok);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(ok, NS_OK);
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
NS_ENSURE_TRUE(ssm->ScriptAllowed(js::GetGlobalForObjectCrossCompartment(aScopeObject)), NS_OK);
mozilla::Maybe<AutoDontReportUncaught> dontReport;
if (!aEvaluateOptions.reportUncaught) {

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

@ -120,14 +120,12 @@ CallbackObject::CallSetup::CallSetup(JS::Handle<JSObject*> aCallback,
if (mIsMainThread) {
// Check that it's ok to run this callback at all.
// FIXME: Bug 807371: we want a less silly check here.
// Make sure to unwrap aCallback before passing it in, because
// getting principals from wrappers is silly.
nsresult rv = nsContentUtils::GetSecurityManager()->
CheckFunctionAccess(cx, js::UncheckedUnwrap(aCallback), nullptr);
// Make sure to unwrap aCallback before passing it in to get the global of
// the callback object, not the wrapper.
bool allowed = nsContentUtils::GetSecurityManager()->
ScriptAllowed(js::GetGlobalForObjectCrossCompartment(js::UncheckedUnwrap(aCallback)));
if (NS_FAILED(rv)) {
// Security check failed. We're done here.
if (!allowed) {
return;
}
}

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

@ -249,7 +249,14 @@ AdapterPropertiesChangeCallback(bt_status_t aStatus, int aNumProperties,
propertiesArray.AppendElement(
BluetoothNamedValue(NS_LITERAL_STRING("Name"), propertyValue));
} else if (p.type == BT_PROPERTY_ADAPTER_SCAN_MODE) {
propertyValue = sAdapterDiscoverable = *(uint32_t*)p.val;
bt_scan_mode_t newMode = *(bt_scan_mode_t*)p.val;
if (newMode == BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
propertyValue = sAdapterDiscoverable = true;
} else {
propertyValue = sAdapterDiscoverable = false;
}
propertiesArray.AppendElement(
BluetoothNamedValue(NS_LITERAL_STRING("Discoverable"), propertyValue));
} else if (p.type == BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT) {
@ -637,9 +644,12 @@ ReplyStatusError(BluetoothReplyRunnable* aBluetoothReplyRunnable,
int aStatusCode, const nsAString& aCustomMsg)
{
MOZ_ASSERT(aBluetoothReplyRunnable, "Reply runnable is nullptr");
nsAutoString replyError;
BT_LOGR("%s: error code(%d)", __FUNCTION__, aStatusCode);
nsAutoString replyError;
replyError.Assign(aCustomMsg);
if (aStatusCode == BT_STATUS_BUSY) {
replyError.AppendLiteral(":BT_STATUS_BUSY");
} else if (aStatusCode == BT_STATUS_NOT_READY) {
@ -840,6 +850,7 @@ BluetoothServiceBluedroid::SetProperty(BluetoothObjectType aType,
const nsString propName = aValue.name();
bt_property_t prop;
bt_scan_mode_t scanMode;
nsString str;
// For Bluedroid, it's necessary to check property name for SetProperty
@ -863,22 +874,23 @@ BluetoothServiceBluedroid::SetProperty(BluetoothObjectType aType,
prop.val = (void*)name;
prop.len = strlen(name);
} else if (aValue.value().type() == BluetoothValue::Tbool) {
bt_scan_mode_t mode = aValue.value().get_bool() ?
BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE :
BT_SCAN_MODE_CONNECTABLE;
bt_scan_mode_t* sss = &mode;
prop.val = (void*)sss;
prop.len = sizeof(sss);
scanMode = aValue.value().get_bool() ?
BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE :
BT_SCAN_MODE_CONNECTABLE;
prop.val = (void*)&scanMode;
prop.len = sizeof(scanMode);
} else {
BT_LOGR("SetProperty but the property cannot be recognized correctly.");
return NS_OK;
}
sSetPropertyRunnableArray.AppendElement(aRunnable);
int ret = sBtInterface->set_adapter_property(&prop);
if (ret != BT_STATUS_SUCCESS)
int ret = sBtInterface->set_adapter_property(&prop);
if (ret != BT_STATUS_SUCCESS) {
ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("SetProperty"));
}
return NS_OK;
}

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

@ -29,6 +29,11 @@ const browserElementTestHelpers = {
}
},
_setPrefs: function() {
this.lockTestReady();
SpecialPowers.pushPrefEnv({'set': Array.slice(arguments)}, this.unlockTestReady.bind(this));
},
_testReadyLockCount: 0,
_firedTestReady: false,
lockTestReady: function() {
@ -44,9 +49,11 @@ const browserElementTestHelpers = {
},
enableProcessPriorityManager: function() {
this._setPref('dom.ipc.processPriorityManager.testMode', true);
this._setPref('dom.ipc.processPriorityManager.enabled', true);
this._setPref('dom.ipc.processPriorityManager.backgroundLRUPoolLevels', 2);
this._setPrefs(
['dom.ipc.processPriorityManager.testMode', true],
['dom.ipc.processPriorityManager.enabled', true],
['dom.ipc.processPriorityManager.backgroundLRUPoolLevels', 2]
);
},
setEnabledPref: function(value) {

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

@ -289,11 +289,12 @@ parent:
ContentReceivedTouch(ScrollableLayerGuid aGuid, bool aPreventDefault);
/**
* Updates the parent's zoom constraints for this tab. The zoom controller
* code lives on the parent side and so this allows it to have up-to-date
* zoom constraints.
* Updates the zoom constraints for a scrollable frame in this tab.
* The zoom controller code lives on the parent side and so this allows it to
* have up-to-date zoom constraints.
*/
UpdateZoomConstraints(bool aAllowZoom, CSSToScreenScale aMinZoom, CSSToScreenScale aMaxZoom);
UpdateZoomConstraints(uint32_t aPresShellId, ViewID aViewId,
bool aAllowZoom, CSSToScreenScale aMinZoom, CSSToScreenScale aMaxZoom);
/**
* Notifies the parent about a scroll event. The pres shell ID and

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

@ -537,8 +537,17 @@ TabChild::HandlePossibleViewportChange()
nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
uint32_t presShellId;
ViewID viewId;
if (!APZCCallbackHelper::GetScrollIdentifiers(document->GetDocumentElement(),
&presShellId, &viewId)) {
return;
}
nsViewportInfo viewportInfo = nsContentUtils::GetViewportInfo(document, mInnerSize);
SendUpdateZoomConstraints(viewportInfo.IsZoomAllowed(),
SendUpdateZoomConstraints(presShellId,
viewId,
viewportInfo.IsZoomAllowed(),
viewportInfo.GetMinZoom(),
viewportInfo.GetMaxZoom());

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

@ -1626,12 +1626,14 @@ TabParent::RecvZoomToRect(const uint32_t& aPresShellId,
}
bool
TabParent::RecvUpdateZoomConstraints(const bool& aAllowZoom,
TabParent::RecvUpdateZoomConstraints(const uint32_t& aPresShellId,
const ViewID& aViewId,
const bool& aAllowZoom,
const CSSToScreenScale& aMinZoom,
const CSSToScreenScale& aMaxZoom)
{
if (RenderFrameParent* rfp = GetRenderFrame()) {
rfp->UpdateZoomConstraints(aAllowZoom, aMinZoom, aMaxZoom);
rfp->UpdateZoomConstraints(aPresShellId, aViewId, aAllowZoom, aMinZoom, aMaxZoom);
}
return true;
}

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

@ -165,7 +165,9 @@ public:
virtual bool RecvZoomToRect(const uint32_t& aPresShellId,
const ViewID& aViewId,
const CSSRect& aRect);
virtual bool RecvUpdateZoomConstraints(const bool& aAllowZoom,
virtual bool RecvUpdateZoomConstraints(const uint32_t& aPresShellId,
const ViewID& aViewId,
const bool& aAllowZoom,
const CSSToScreenScale& aMinZoom,
const CSSToScreenScale& aMaxZoom);
virtual bool RecvUpdateScrollOffset(const uint32_t& aPresShellId, const ViewID& aViewId, const CSSIntPoint& aScrollOffset);

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

@ -95,6 +95,15 @@ this.SystemMessagePermissionsTable = {
"cdma-info-rec-received": {
"mobileconnection": []
},
"nfc-manager-tech-discovered": {
"nfc-manager": []
},
"nfc-manager-tech-lost": {
"nfc-manager": []
},
"nfc-powerlevel-change": {
"settings": ["read", "write"]
}
};
this.SystemMessagePermissionsChecker = {

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

@ -97,6 +97,9 @@ if CONFIG['MOZ_PAY']:
if CONFIG['MOZ_GAMEPAD']:
PARALLEL_DIRS += ['gamepad']
if CONFIG['MOZ_NFC']:
PARALLEL_DIRS += ['nfc']
# bindings/test is here, because it needs to build after bindings/, and
# we build subdirectories before ourselves.
TEST_DIRS += [

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

@ -211,11 +211,12 @@ interface nsIDOMTCPSocket : nsISupports
};
/*
* Internal interfaces for use in cross-process socket implementation.
* This interface is implemented in TCPSocket.js as an internal interfaces
* for use in cross-process socket implementation.
* Needed to account for multiple possible types that can be provided to
* the socket callbacks as arguments.
*/
[scriptable, uuid(234c664c-3d6c-4859-b45c-4e9a98cb5bdc)]
[scriptable, uuid(017f130f-2477-4215-8783-57eada957699)]
interface nsITCPSocketInternal : nsISupports {
// Trigger the callback for |type| and provide a DOMError() object with the given data
void callListenerError(in DOMString type, in DOMString name);
@ -229,8 +230,20 @@ interface nsITCPSocketInternal : nsISupports {
// Trigger the callback for |type| with no argument
void callListenerVoid(in DOMString type);
// Update the DOM object's readyState and bufferedAmount values with the provided data
void updateReadyStateAndBuffered(in DOMString readyState, in uint32_t bufferedAmount);
// Update the DOM object's readyState.
// @param readyState
// new ready state to be set to TCPSocket.
void updateReadyState(in DOMString readyState);
// Update the DOM object's bufferedAmount value with a tracking number to
// ensure the update request is sent after child's send() invocation.
// @param bufferedAmount
// TCPSocket parent's bufferedAmount.
// @param trackingNumber
// A number to ensure the bufferedAmount is updated after data
// from child are sent to parent.
void updateBufferedAmount(in uint32_t bufferedAmount,
in uint32_t trackingNumber);
// Create a socket object on the parent side.
// This is called in accepting any open request on the parent side.
@ -259,6 +272,18 @@ interface nsITCPSocketInternal : nsISupports {
// Set App ID.
void setAppId(in unsigned long appId);
// Set a callback that handles the request from a TCP socket parent when that
// socket parent wants to notify that its bufferedAmount is updated.
void setOnUpdateBufferedAmountHandler(in jsval handler);
// Providing child process with ability to pass more arguments to parent's
// send() function.
// @param trackingNumber
// To ensure the request to update bufferedAmount in child is after
// lastest send() invocation from child.
void onRecvSendFromChild(in jsval data, in unsigned long byteOffset,
in unsigned long byteLength, in unsigned long trackingNumber);
};
/**

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

@ -8,22 +8,26 @@ interface nsITCPSocketInternal;
interface nsIDOMWindow;
// Interface to allow the content process socket to reach the IPC bridge.
[scriptable, uuid(ada5342d-6d45-4ff1-a7d3-6a4b150d0385)]
// Implemented in C++ as TCPSocketChild, referenced as _socketBridge in TCPSocket.js
[scriptable, uuid(292ebb3a-beac-4e06-88b0-b5b4e88ebd1c)]
interface nsITCPSocketChild : nsISupports
{
// Tell the chrome process to open a corresponding connection with the given parameters
[implicit_jscontext]
void open(in nsITCPSocketInternal socket, in DOMString host,
in unsigned short port, in boolean ssl, in DOMString binaryType,
in nsIDOMWindow window, in jsval windowVal);
void sendOpen(in nsITCPSocketInternal socket, in DOMString host,
in unsigned short port, in boolean ssl, in DOMString binaryType,
in nsIDOMWindow window, in jsval windowVal);
// Tell the chrome process to perform send and update the tracking number.
[implicit_jscontext]
void sendSend(in jsval data, in unsigned long byteOffset,
in unsigned long byteLength, in unsigned long trackingNumber);
// Tell the chrome process to perform equivalent operations to all following methods
[implicit_jscontext]
void send(in jsval data, in unsigned long byteOffset, in unsigned long byteLength);
void resume();
void suspend();
void close();
void startTLS();
void sendResume();
void sendSuspend();
void sendClose();
void sendStartTLS();
/**
* Initialize the TCP socket on the child side for IPC. It is called from the child side,

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

@ -9,20 +9,28 @@ interface nsIDOMTCPServerSocket;
interface nsITCPServerSocketParent;
interface nsITCPSocketIntermediary;
// Interface required to allow the TCP socket object in the parent process
// to talk to the parent IPC actor
[scriptable, uuid(123f654b-4435-43c8-8447-db1b5420a1c2)]
// Interface required to allow the TCP socket object (TCPSocket.js) in the
// parent process to talk to the parent IPC actor, TCPSocketParent, which
// is written in C++.
[scriptable, uuid(868662a4-681c-4b89-9f02-6fe5b7ace265)]
interface nsITCPSocketParent : nsISupports
{
[implicit_jscontext] void initJS(in jsval intermediary);
// Trigger a callback in the content process for |type|, providing a serialized
// argument of |data|, and update the child's readyState and bufferedAmount values
// with the given values.
[implicit_jscontext] void sendCallback(in DOMString type,
in jsval data,
in DOMString readyState,
in uint32_t bufferedAmount);
// argument of |data|, and update the child's readyState value with the given
// values.
//
// @param type
// Event type: 'onopen', 'ondata', 'onerror' or 'onclose'. 'odrain' is
// controlled by child.
// @param data
// Serialized data that is passed to event handler.
// @param readyState
// Current ready state.
[implicit_jscontext] void sendEvent(in DOMString type,
in jsval data,
in DOMString readyState);
// Initialize a parent socket object. It is called from the parent side socket,
// which is generated in accepting any open request on the parent side.
@ -34,11 +42,27 @@ interface nsITCPSocketParent : nsISupports
// Intermediate class object. See nsITCPSocketIntermediary.
[implicit_jscontext] void setSocketAndIntermediary(in nsIDOMTCPSocket socket,
in nsITCPSocketIntermediary intermediary);
// When parent's buffered amount is updated and it wants to inform child to
// update the bufferedAmount as well.
//
// @param bufferedAmount
// The new value of bufferedAmount that is going to be set to child's
// bufferedAmount.
// @param trackingNumber
// Parent's current tracking number, reflecting the number of calls to
// send() on the child process. This number is sent back to the child
// to make sure the bufferedAmount updated on the child will correspond
// to the latest call of send().
void sendUpdateBufferedAmount(in uint32_t bufferedAmount, in uint32_t trackingNumber);
};
// Intermediate class to handle sending multiple possible data types
// and kicking off the chrome process socket object's connection.
[scriptable, uuid(be67b1b8-03b0-4171-a791-d004458021b6)]
// This interface is the bridge of TCPSocketParent, which is written in C++,
// and TCPSocket, which is written in Javascript. TCPSocketParentIntermediary
// implements nsITCPSocketIntermediary in Javascript.
[scriptable, uuid(c434224a-dbb7-4869-8b2b-e49cee990e85)]
interface nsITCPSocketIntermediary : nsISupports {
// Open the connection to the server with the given parameters
nsIDOMTCPSocket open(in nsITCPSocketParent parent,
@ -51,9 +75,9 @@ interface nsITCPSocketIntermediary : nsISupports {
in unsigned short port, in unsigned short backlog,
in DOMString binaryType);
// Send a basic string along the connection
void sendString(in DOMString data);
// Called when received a child request to send a string.
void onRecvSendString(in DOMString data, in uint32_t trackingNumber);
// Send a typed array
void sendArrayBuffer(in jsval data);
// Called when received a child request to send an array buffer.
void onRecvSendArrayBuffer(in jsval data, in uint32_t trackingNumber);
};

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

@ -362,6 +362,7 @@ this.NetworkStatsService = {
this.updateQueue.push({netId: aNetId, callbacks: [aCallback]});
} else {
this.updateQueue[index].callbacks.push(aCallback);
return;
}
// Call the function that process the elements of the queue.

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

@ -35,16 +35,35 @@ protocol PTCPSocket
manager PNecko;
parent:
// Forward calling to child's open() method to parent, expect TCPOptions
// is expanded to |useSSL| (from TCPOptions.useSecureTransport) and
// |binaryType| (from TCPOption.binaryType).
Open(nsString host, uint16_t port, bool useSSL, nsString binaryType);
Data(SendableData data);
// When child's send() is called, this message requrests parent to send
// data and update it's trackingNumber.
Data(SendableData data, uint32_t trackingNumber);
// Forward calling to child's upgradeToSecure() method to parent.
StartTLS();
// Forward calling to child's send() method to parent.
Suspend();
// Forward calling to child's resume() method to parent.
Resume();
// Forward calling to child's close() method to parent.
Close();
child:
Callback(nsString type, CallbackData data,
nsString readyState, uint32_t bufferedAmount);
// Forward events that are dispatched by parent.
Callback(nsString type, CallbackData data, nsString readyState);
// Update child's bufferedAmount when parent's bufferedAmount is updated.
// trackingNumber is also passed back to child to ensure the bufferedAmount
// is corresponding the last call to send().
UpdateBufferedAmount(uint32_t bufferedAmount, uint32_t trackingNumber);
both:
RequestDelete();

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

@ -162,6 +162,10 @@ TCPSocket.prototype = {
_waitingForStartTLS: false,
_pendingDataAfterStartTLS: [],
// Used to notify when update bufferedAmount is updated.
_onUpdateBufferedAmount: null,
_trackingNumber: 0,
#ifdef MOZ_WIDGET_GONK
// Network statistics (Gonk-specific feature)
_txBytes: 0,
@ -242,6 +246,12 @@ TCPSocket.prototype = {
.createTransport(options, 1, host, port, null);
},
_sendBufferedAmount: function ts_sendBufferedAmount() {
if (this._onUpdateBufferedAmount) {
this._onUpdateBufferedAmount(this.bufferedAmount, this._trackingNumber);
}
},
_ensureCopying: function ts_ensureCopying() {
let self = this;
if (this._asyncCopierActive) {
@ -254,6 +264,7 @@ TCPSocket.prototype = {
onStopRequest: function ts_output_onStopRequest(request, context, status) {
self._asyncCopierActive = false;
self._multiplexStream.removeStream(0);
self._sendBufferedAmount();
if (!Components.isSuccessCode(status)) {
// Note that we can/will get an error here as well as in the
@ -280,7 +291,9 @@ TCPSocket.prototype = {
}
}
if (self._waitingForDrain) {
// If we have a callback to update bufferedAmount, we let child to
// decide whether ondrain should be dispatched.
if (self._waitingForDrain && !self._onUpdateBufferedAmount) {
self._waitingForDrain = false;
self.callListener("drain");
}
@ -382,9 +395,36 @@ TCPSocket.prototype = {
this.callListener(type);
},
updateReadyStateAndBuffered: function ts_setReadyState(readyState, bufferedAmount) {
/**
* This method is expected to be called by TCPSocketChild to update child's
* readyState.
*/
updateReadyState: function ts_updateReadyState(readyState) {
if (!this._inChild) {
LOG("Calling updateReadyState in parent, which should only be called " +
"in child");
return;
}
this._readyState = readyState;
},
updateBufferedAmount: function ts_updateBufferedAmount(bufferedAmount, trackingNumber) {
if (trackingNumber != this._trackingNumber) {
LOG("updateBufferedAmount is called but trackingNumber is not matched " +
"parent's trackingNumber: " + trackingNumber + ", child's trackingNumber: " +
this._trackingNumber);
return;
}
this._bufferedAmount = bufferedAmount;
if (bufferedAmount == 0) {
if (this._waitingForDrain) {
this._waitingForDrain = false;
this.callListener("drain");
}
} else {
LOG("bufferedAmount is updated but haven't reaches zero. bufferedAmount: " +
bufferedAmount);
}
},
createAcceptedParent: function ts_createAcceptedParent(transport, binaryType) {
@ -420,6 +460,25 @@ TCPSocket.prototype = {
#endif
},
setOnUpdateBufferedAmountHandler: function(aFunction) {
if (typeof(aFunction) == 'function') {
this._onUpdateBufferedAmount = aFunction;
} else {
throw new Error("only function can be passed to " +
"setOnUpdateBufferedAmountHandler");
}
},
/**
* Handle the requst of sending data and update trackingNumber from
* child.
* This function is expected to be called by TCPSocketChild.
*/
onRecvSendFromChild: function(data, byteOffset, byteLength, trackingNumber) {
this._trackingNumber = trackingNumber;
this.send(data, byteOffset, byteLength);
},
/* end nsITCPSocketInternal methods */
initWindowless: function ts_initWindowless() {
@ -517,8 +576,8 @@ TCPSocket.prototype = {
if (this._inChild) {
that._socketBridge = Cc["@mozilla.org/tcp-socket-child;1"]
.createInstance(Ci.nsITCPSocketChild);
that._socketBridge.open(that, host, port, !!that._ssl,
that._binaryType, this.useWin, this.useWin || this);
that._socketBridge.sendOpen(that, host, port, !!that._ssl,
that._binaryType, this.useWin, this.useWin || this);
return that;
}
@ -551,7 +610,7 @@ TCPSocket.prototype = {
this._ssl = 'ssl';
if (this._inChild) {
this._socketBridge.startTLS();
this._socketBridge.sendStartTLS();
return;
}
@ -585,7 +644,7 @@ TCPSocket.prototype = {
this._readyState = kCLOSING;
if (this._inChild) {
this._socketBridge.close();
this._socketBridge.sendClose();
return;
}
@ -605,15 +664,27 @@ TCPSocket.prototype = {
}
if (this._inChild) {
this._socketBridge.send(data, byteOffset, byteLength);
this._socketBridge.sendSend(data, byteOffset, byteLength, ++this._trackingNumber);
}
let length = this._binaryType === "arraybuffer" ? byteLength : data.length;
let newBufferedAmount = this.bufferedAmount + length;
let bufferFull = newBufferedAmount >= BUFFER_SIZE;
if (bufferFull) {
// If we buffered more than some arbitrary amount of data,
// (65535 right now) we should tell the caller so they can
// wait until ondrain is called if they so desire. Once all the
// buffered data has been written to the socket, ondrain is
// called.
this._waitingForDrain = true;
}
var newBufferedAmount = this.bufferedAmount + length;
var bufferNotFull = newBufferedAmount < BUFFER_SIZE;
if (this._inChild) {
return bufferNotFull;
// In child, we just add buffer length to our bufferedAmount and let
// parent to update our bufferedAmount when data have been sent.
this._bufferedAmount = newBufferedAmount;
return !bufferFull;
}
let new_stream;
@ -633,15 +704,6 @@ TCPSocket.prototype = {
this._multiplexStream.appendStream(new_stream);
}
if (newBufferedAmount >= BUFFER_SIZE) {
// If we buffered more than some arbitrary amount of data,
// (65535 right now) we should tell the caller so they can
// wait until ondrain is called if they so desire. Once all the
//buffered data has been written to the socket, ondrain is
// called.
this._waitingForDrain = true;
}
this._ensureCopying();
#ifdef MOZ_WIDGET_GONK
@ -650,12 +712,12 @@ TCPSocket.prototype = {
this._saveNetworkStats(false);
#endif
return bufferNotFull;
return !bufferFull;
},
suspend: function ts_suspend() {
if (this._inChild) {
this._socketBridge.suspend();
this._socketBridge.sendSuspend();
return;
}
@ -668,7 +730,7 @@ TCPSocket.prototype = {
resume: function ts_resume() {
if (this._inChild) {
this._socketBridge.resume();
this._socketBridge.sendResume();
return;
}

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

@ -77,10 +77,11 @@ TCPSocketChild::TCPSocketChild()
}
NS_IMETHODIMP
TCPSocketChild::Open(nsITCPSocketInternal* aSocket, const nsAString& aHost,
uint16_t aPort, bool aUseSSL, const nsAString& aBinaryType,
nsIDOMWindow* aWindow, const JS::Value& aWindowObj,
JSContext* aCx)
TCPSocketChild::SendOpen(nsITCPSocketInternal* aSocket,
const nsAString& aHost, uint16_t aPort,
bool aUseSSL, const nsAString& aBinaryType,
nsIDOMWindow* aWindow, const JS::Value& aWindowObj,
JSContext* aCx)
{
mSocket = aSocket;
@ -91,7 +92,8 @@ TCPSocketChild::Open(nsITCPSocketInternal* aSocket, const nsAString& aHost,
}
AddIPDLReference();
gNeckoChild->SendPTCPSocketConstructor(this);
SendOpen(nsString(aHost), aPort, aUseSSL, nsString(aBinaryType));
PTCPSocketChild::SendOpen(nsString(aHost), aPort,
aUseSSL, nsString(aBinaryType));
return NS_OK;
}
@ -115,13 +117,22 @@ TCPSocketChild::~TCPSocketChild()
{
}
bool
TCPSocketChild::RecvUpdateBufferedAmount(const uint32_t& aBuffered,
const uint32_t& aTrackingNumber)
{
if (NS_FAILED(mSocket->UpdateBufferedAmount(aBuffered, aTrackingNumber))) {
NS_ERROR("Shouldn't fail!");
}
return true;
}
bool
TCPSocketChild::RecvCallback(const nsString& aType,
const CallbackData& aData,
const nsString& aReadyState,
const uint32_t& aBuffered)
const nsString& aReadyState)
{
if (NS_FAILED(mSocket->UpdateReadyStateAndBuffered(aReadyState, aBuffered)))
if (NS_FAILED(mSocket->UpdateReadyState(aReadyState)))
NS_ERROR("Shouldn't fail!");
nsresult rv = NS_ERROR_FAILURE;
@ -159,46 +170,46 @@ TCPSocketChild::RecvCallback(const nsString& aType,
}
NS_IMETHODIMP
TCPSocketChild::StartTLS()
TCPSocketChild::SendStartTLS()
{
SendStartTLS();
PTCPSocketChild::SendStartTLS();
return NS_OK;
}
NS_IMETHODIMP
TCPSocketChild::Suspend()
TCPSocketChild::SendSuspend()
{
SendSuspend();
PTCPSocketChild::SendSuspend();
return NS_OK;
}
NS_IMETHODIMP
TCPSocketChild::Resume()
TCPSocketChild::SendResume()
{
SendResume();
PTCPSocketChild::SendResume();
return NS_OK;
}
NS_IMETHODIMP
TCPSocketChild::Close()
TCPSocketChild::SendClose()
{
SendClose();
PTCPSocketChild::SendClose();
return NS_OK;
}
NS_IMETHODIMP
TCPSocketChild::Send(const JS::Value& aData,
uint32_t aByteOffset,
uint32_t aByteLength,
JSContext* aCx)
TCPSocketChild::SendSend(const JS::Value& aData,
uint32_t aByteOffset,
uint32_t aByteLength,
uint32_t aTrackingNumber,
JSContext* aCx)
{
if (aData.isString()) {
JSString* jsstr = aData.toString();
nsDependentJSString str;
bool ok = str.init(aCx, jsstr);
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
SendData(str);
SendData(str, aTrackingNumber);
} else {
NS_ENSURE_TRUE(aData.isObject(), NS_ERROR_FAILURE);
JS::Rooted<JSObject*> obj(aCx, &aData.toObject());
@ -216,15 +227,15 @@ TCPSocketChild::Send(const JS::Value& aData,
}
InfallibleTArray<uint8_t> arr;
arr.SwapElements(fallibleArr);
SendData(arr);
SendData(arr, aTrackingNumber);
}
return NS_OK;
}
NS_IMETHODIMP
TCPSocketChild::SetSocketAndWindow(nsITCPSocketInternal *aSocket,
const JS::Value& aWindowObj,
JSContext* aCx)
const JS::Value& aWindowObj,
JSContext* aCx)
{
mSocket = aSocket;
MOZ_ASSERT(aWindowObj.isObject());

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

@ -44,9 +44,10 @@ public:
virtual bool RecvCallback(const nsString& aType,
const CallbackData& aData,
const nsString& aReadyState,
const uint32_t& aBuffered) MOZ_OVERRIDE;
const nsString& aReadyState) MOZ_OVERRIDE;
virtual bool RecvRequestDelete() MOZ_OVERRIDE;
virtual bool RecvUpdateBufferedAmount(const uint32_t& aBufferred,
const uint32_t& aTrackingNumber) MOZ_OVERRIDE;
private:
JSObject* mWindowObj;
};

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

@ -35,7 +35,7 @@ FireInteralError(mozilla::net::PTCPSocketParent* aActor, uint32_t aLineNo)
mozilla::unused <<
aActor->SendCallback(NS_LITERAL_STRING("onerror"),
TCPError(NS_LITERAL_STRING("InvalidStateError")),
NS_LITERAL_STRING("connecting"), 0);
NS_LITERAL_STRING("connecting"));
}
NS_IMPL_CYCLE_COLLECTION_2(TCPSocketParentBase, mSocket, mIntermediary)
@ -156,7 +156,8 @@ TCPSocketParent::RecvResume()
}
bool
TCPSocketParent::RecvData(const SendableData& aData)
TCPSocketParent::RecvData(const SendableData& aData,
const uint32_t& aTrackingNumber)
{
NS_ENSURE_TRUE(mIntermediary, true);
@ -168,13 +169,13 @@ TCPSocketParent::RecvData(const SendableData& aData)
JS::Rooted<JS::Value> val(cx);
JS::Rooted<JSObject*> obj(cx, mIntermediaryObj);
IPC::DeserializeArrayBuffer(obj, aData.get_ArrayOfuint8_t(), &val);
rv = mIntermediary->SendArrayBuffer(val);
rv = mIntermediary->OnRecvSendArrayBuffer(val, aTrackingNumber);
NS_ENSURE_SUCCESS(rv, true);
break;
}
case SendableData::TnsString:
rv = mIntermediary->SendString(aData.get_nsString());
rv = mIntermediary->OnRecvSendString(aData.get_nsString(), aTrackingNumber);
NS_ENSURE_SUCCESS(rv, true);
break;
@ -194,9 +195,8 @@ TCPSocketParent::RecvClose()
}
NS_IMETHODIMP
TCPSocketParent::SendCallback(const nsAString& aType, const JS::Value& aDataVal,
const nsAString& aReadyState, uint32_t aBuffered,
JSContext* aCx)
TCPSocketParent::SendEvent(const nsAString& aType, const JS::Value& aDataVal,
const nsAString& aReadyState, JSContext* aCx)
{
if (!mIPCOpen) {
NS_WARNING("Dropping callback due to no IPC connection");
@ -255,7 +255,7 @@ TCPSocketParent::SendCallback(const nsAString& aType, const JS::Value& aDataVal,
}
mozilla::unused <<
PTCPSocketParent::SendCallback(nsString(aType), data,
nsString(aReadyState), aBuffered);
nsString(aReadyState));
return NS_OK;
}
@ -269,6 +269,15 @@ TCPSocketParent::SetSocketAndIntermediary(nsIDOMTCPSocket *socket,
return NS_OK;
}
NS_IMETHODIMP
TCPSocketParent::SendUpdateBufferedAmount(uint32_t aBufferedAmount,
uint32_t aTrackingNumber)
{
mozilla::unused << PTCPSocketParent::SendUpdateBufferedAmount(aBufferedAmount,
aTrackingNumber);
return NS_OK;
}
void
TCPSocketParent::ActorDestroy(ActorDestroyReason why)
{

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

@ -51,7 +51,8 @@ public:
virtual bool RecvSuspend() MOZ_OVERRIDE;
virtual bool RecvResume() MOZ_OVERRIDE;
virtual bool RecvClose() MOZ_OVERRIDE;
virtual bool RecvData(const SendableData& aData) MOZ_OVERRIDE;
virtual bool RecvData(const SendableData& aData,
const uint32_t& aTrackingNumber) MOZ_OVERRIDE;
virtual bool RecvRequestDelete() MOZ_OVERRIDE;
private:

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

@ -20,15 +20,21 @@ TCPSocketParentIntermediary.prototype = {
// Create handlers for every possible callback that attempt to trigger
// corresponding callbacks on the child object.
["open", "drain", "data", "error", "close"].forEach(
// ondrain event is not forwarded, since the decision of firing ondrain
// is made in child.
["open", "data", "error", "close"].forEach(
function(p) {
socket["on" + p] = function(data) {
aParentSide.sendCallback(p, data.data, socket.readyState,
socket.bufferedAmount);
aParentSide.sendEvent(p, data.data, socket.readyState,
socket.bufferedAmount);
};
}
);
},
},
_onUpdateBufferedAmountHandler: function(aParentSide, aBufferedAmount, aTrackingNumber) {
aParentSide.sendUpdateBufferedAmount(aBufferedAmount, aTrackingNumber);
},
open: function(aParentSide, aHost, aPort, aUseSSL, aBinaryType, aAppId) {
let baseSocket = Cc["@mozilla.org/tcp-socket;1"].createInstance(Ci.nsIDOMTCPSocket);
@ -41,6 +47,10 @@ TCPSocketParentIntermediary.prototype = {
socketInternal.setAppId(aAppId);
}
// Handle parent's request to update buffered amount.
socketInternal.setOnUpdateBufferedAmountHandler(
this._onUpdateBufferedAmountHandler.bind(this, aParentSide));
// Handlers are set to the JS-implemented socket object on the parent side.
this._setCallbacks(aParentSide, socket);
return socket;
@ -79,12 +89,15 @@ TCPSocketParentIntermediary.prototype = {
return serverSocket;
},
sendString: function(aData) {
return this._socket.send(aData);
onRecvSendString: function(aData, aTrackingNumber) {
let socketInternal = this._socket.QueryInterface(Ci.nsITCPSocketInternal);
return socketInternal.onRecvSendFromChild(aData, 0, 0, aTrackingNumber);
},
sendArrayBuffer: function(aData) {
return this._socket.send(aData, 0, aData.byteLength);
onRecvSendArrayBuffer: function(aData, aTrackingNumber) {
let socketInternal = this._socket.QueryInterface(Ci.nsITCPSocketInternal);
return socketInternal.onRecvSendFromChild(aData, 0, aData.byteLength,
aTrackingNumber);
},
classID: Components.ID("{afa42841-a6cb-4a91-912f-93099f6a3d18}"),

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

@ -80,6 +80,11 @@ function get_platform() {
return xulRuntime.OS;
}
function is_content() {
return this._inChild = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
}
/**
* Spin up a listening socket and associate at most one live, accepted socket
* with ourselves.
@ -418,9 +423,15 @@ function drainTwice() {
['ondrain', 'ondrain2',
'ondata', 'ondata2',
'serverclose', 'clientclose']);
let ondrainCalled = false,
ondataCalled = false;
function maybeSendNextData() {
if (!ondrainCalled || !ondataCalled) {
// make sure server got data and client got ondrain.
return;
}
function serverSideCallback() {
yays.ondata();
server.ondata = makeExpectData(
"ondata2", BIG_TYPED_ARRAY_2, false, yays.ondata2);
@ -433,12 +444,24 @@ function drainTwice() {
sock.close();
}
function clientOndrain() {
yays.ondrain();
ondrainCalled = true;
maybeSendNextData();
}
function serverSideCallback() {
yays.ondata();
ondataCalled = true;
maybeSendNextData();
}
server.onclose = yays.serverclose;
server.ondata = makeExpectData(
"ondata", BIG_TYPED_ARRAY, false, serverSideCallback);
sock.onclose = yays.clientclose;
sock.ondrain = yays.ondrain;
sock.ondrain = clientOndrain;
if (sock.send(BIG_ARRAY_BUFFER)) {
throw new Error("sock.send(BIG_TYPED_ARRAY) did not return false to indicate buffering");
@ -482,6 +505,62 @@ function bufferTwice() {
}
}
// Test child behavior when child thinks it's buffering but parent doesn't
// buffer.
// 1. set bufferedAmount of content socket to a value that will make next
// send() call return false.
// 2. send a small data to make send() return false, but it won't make
// parent buffer.
// 3. we should get a ondrain.
function childbuffered() {
let yays = makeJointSuccess(['ondrain', 'serverdata',
'clientclose', 'serverclose']);
sock.ondrain = function() {
yays.ondrain();
sock.close();
};
server.ondata = makeExpectData(
'ondata', DATA_ARRAY, false, yays.serverdata);
let internalSocket = sock.QueryInterface(Ci.nsITCPSocketInternal);
internalSocket.updateBufferedAmount(65535, // almost reach buffering threshold
0);
if (sock.send(DATA_ARRAY_BUFFER)) {
do_throw("expected sock.send to return false.");
}
sock.onclose = yays.clientclose;
server.onclose = yays.serverclose;
}
// Test child's behavior when send() of child return true but parent buffers
// data.
// 1. send BIG_ARRAY to make parent buffer. This would make child wait for
// drain as well.
// 2. set child's bufferedAmount to zero, so child will no longer wait for
// drain but parent will dispatch a drain event.
// 3. wait for 1 second, to make sure there's no ondrain event dispatched in
// child.
function childnotbuffered() {
let yays = makeJointSuccess(['serverdata', 'clientclose', 'serverclose']);
server.ondata = makeExpectData('ondata', BIG_ARRAY, false, yays.serverdata);
if (sock.send(BIG_ARRAY_BUFFER)) {
do_throw("sock.send(BIG_TYPED_ARRAY) did not return false to indicate buffering");
}
let internalSocket = sock.QueryInterface(Ci.nsITCPSocketInternal);
internalSocket.updateBufferedAmount(0, // setting zero will clear waitForDrain in sock.
1);
// shouldn't get ondrain, even after parent have cleared its buffer.
sock.ondrain = makeFailureCase('drain');
sock.onclose = yays.clientclose;
server.onclose = yays.serverclose;
do_timeout(1000, function() {
sock.close();
});
};
// - connect, data and events work both ways
add_test(connectSock);
add_test(sendData);
@ -513,6 +592,14 @@ add_test(drainTwice);
add_test(connectSock);
add_test(bufferTwice);
if (is_content()) {
add_test(connectSock);
add_test(childnotbuffered);
add_test(connectSock);
add_test(childbuffered);
}
// clean up
add_test(cleanup);

64
dom/nfc/MozNdefRecord.cpp Normal file
Просмотреть файл

@ -0,0 +1,64 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
/* Copyright © 2013 Deutsche Telekom, Inc. */
#include "MozNdefRecord.h"
#include "mozilla/dom/MozNdefRecordBinding.h"
#include "nsContentUtils.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(MozNdefRecord, mWindow)
NS_IMPL_CYCLE_COLLECTING_ADDREF(MozNdefRecord)
NS_IMPL_CYCLE_COLLECTING_RELEASE(MozNdefRecord)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MozNdefRecord)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
/* static */
already_AddRefed<MozNdefRecord>
MozNdefRecord::Constructor(const GlobalObject& aGlobal,
uint8_t aTnf, const nsAString& aType,
const nsAString& aId, const nsAString& aPayload,
ErrorResult& aRv)
{
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aGlobal.GetAsSupports());
if (!win) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
nsRefPtr<MozNdefRecord> ndefrecord =
new MozNdefRecord(win, aTnf, aType, aId, aPayload);
return ndefrecord.forget();
}
MozNdefRecord::MozNdefRecord(nsPIDOMWindow* aWindow,
uint8_t aTnf, const nsAString& aType,
const nsAString& aId, const nsAString& aPayload)
: mTnf(aTnf)
, mType(aType)
, mId(aId)
, mPayload(aPayload)
{
mWindow = aWindow;
SetIsDOMBinding();
}
MozNdefRecord::~MozNdefRecord()
{
}
JSObject*
MozNdefRecord::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
{
return MozNdefRecordBinding::Wrap(aCx, aScope, this);
}
} // namespace dom
} // namespace mozilla

88
dom/nfc/MozNdefRecord.h Normal file
Просмотреть файл

@ -0,0 +1,88 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
/* Copyright © 2013 Deutsche Telekom, Inc. */
#ifndef mozilla_dom_MozNdefRecord_h__
#define mozilla_dom_MozNdefRecord_h__
#include "mozilla/Attributes.h"
#include "mozilla/ErrorResult.h"
#include "nsCycleCollectionParticipant.h"
#include "nsWrapperCache.h"
#include "jsapi.h"
#include "nsIDocument.h"
struct JSContext;
namespace mozilla {
namespace dom {
class MozNdefRecord MOZ_FINAL : public nsISupports,
public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MozNdefRecord)
public:
MozNdefRecord(nsPIDOMWindow* aWindow,
uint8_t aTnf, const nsAString& aType,
const nsAString& aId, const nsAString& aPlayload);
~MozNdefRecord();
nsIDOMWindow* GetParentObject() const
{
return mWindow;
}
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
static already_AddRefed<MozNdefRecord> Constructor(
const GlobalObject& aGlobal,
uint8_t aTnf, const nsAString& aType,
const nsAString& aId,
const nsAString& aPayload,
ErrorResult& aRv);
uint8_t Tnf() const
{
return mTnf;
}
void GetType(nsString& aType) const
{
aType = mType;
}
void GetId(nsString& aId) const
{
aId = mId;
}
void GetPayload(nsString& aPayload) const
{
aPayload = mPayload;
}
private:
MozNdefRecord() MOZ_DELETE;
nsRefPtr<nsPIDOMWindow> mWindow;
uint8_t mTnf;
nsString mType;
nsString mId;
nsString mPayload;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_MozNdefRecord_h__

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше