зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-inbound in mozilla-central.
This commit is contained in:
Коммит
25a3db2998
|
@ -29,8 +29,8 @@
|
|||
function testTabRelations()
|
||||
{
|
||||
this.eventSeq = [
|
||||
new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, tabDocumentAt, 0),
|
||||
new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, tabDocumentAt, 1)
|
||||
new asyncInvokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, tabDocumentAt, 0),
|
||||
new asyncInvokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, tabDocumentAt, 1)
|
||||
];
|
||||
|
||||
this.invoke = function testTabRelations_invoke()
|
||||
|
@ -61,8 +61,10 @@
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Test
|
||||
|
||||
//gA11yEventDumpToConsole = true; // debug stuff
|
||||
|
||||
var gQueue = null;
|
||||
gA11yEventDumpToConsole = true;
|
||||
function doTest()
|
||||
{
|
||||
// Load documents into tabs and wait for DocLoadComplete events caused by
|
||||
|
|
|
@ -28,8 +28,8 @@
|
|||
function testTabHierarchy()
|
||||
{
|
||||
this.eventSeq = [
|
||||
new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, tabDocumentAt, 0),
|
||||
new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, tabDocumentAt, 1)
|
||||
new asyncInvokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, tabDocumentAt, 0),
|
||||
new asyncInvokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, tabDocumentAt, 1)
|
||||
];
|
||||
|
||||
this.invoke = function testTabHierarchy_invoke()
|
||||
|
|
|
@ -354,6 +354,10 @@ pref("browser.dom.window.dump.enabled", false);
|
|||
// installable apps or wifi support.
|
||||
pref("security.fileuri.strict_origin_policy", false);
|
||||
|
||||
// Default Content Security Policy to apply to privileged and certified apps
|
||||
pref("security.apps.privileged.CSP.default", "default-src *; script-src 'self'; object-src 'none'; style-src 'self' 'unsafe-inline'");
|
||||
pref("security.apps.certified.CSP.default", "options inline-script eval-script; default-src *; script-src 'self'; object-src 'none'; style-src 'self'");
|
||||
|
||||
// Temporarily force-enable GL compositing. This is default-disabled
|
||||
// deep within the bowels of the widgetry system. Remove me when GL
|
||||
// compositing isn't default disabled in widget/android.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"tooltool_manifest": "releng-pandaboard.tt",
|
||||
"mock_target": "mozilla-centos6-i386",
|
||||
"mock_packages": ["ccache", "make", "bison", "flex", "gcc", "g++", "mpfr", "zlib-devel", "ncurses-devel", "zip", "autoconf213", "glibc-static", "java-1.6.0-openjdk-devel"]
|
||||
"mock_packages": ["ccache", "make", "bison", "flex", "gcc", "g++", "mpfr", "zlib-devel", "ncurses-devel", "zip", "autoconf213", "glibc-static", "perl-Digest-SHA"]
|
||||
}
|
||||
|
|
|
@ -73,100 +73,103 @@ var stringBundle;
|
|||
|
||||
function saveCanvas(canvas) {
|
||||
const nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
let filePicker = Components.classes["@mozilla.org/filepicker;1"].
|
||||
createInstance(nsIFilePicker);
|
||||
filePicker.init(window, null, nsIFilePicker.modeSave);
|
||||
filePicker.appendFilters(
|
||||
nsIFilePicker.filterImages | nsIFilePicker.filterAll);
|
||||
filePicker.defaultString = "canvas.png";
|
||||
let fp = Components.classes["@mozilla.org/filepicker;1"].
|
||||
createInstance(nsIFilePicker);
|
||||
let fpCallback = function fpCallback_done(aResult) {
|
||||
if (aResult == nsIFilePicker.returnOK ||
|
||||
aResult == nsIFilePicker.returnReplace) {
|
||||
const nsIWebBrowserPersist =
|
||||
Components.interfaces.nsIWebBrowserPersist;
|
||||
let file = fp.file;
|
||||
|
||||
let response = filePicker.show();
|
||||
if (response == nsIFilePicker.returnOK ||
|
||||
response == nsIFilePicker.returnReplace) {
|
||||
const nsIWebBrowserPersist = Components.interfaces.nsIWebBrowserPersist;
|
||||
let file = filePicker.file;
|
||||
// create a data url from the canvas and then create URIs of the
|
||||
// source and targets
|
||||
let io = Components.classes["@mozilla.org/network/io-service;1"].
|
||||
getService(Components.interfaces.nsIIOService);
|
||||
let source = io.newURI(canvas.toDataURL("image/png"), "UTF8", null);
|
||||
let target = io.newFileURI(file);
|
||||
|
||||
// create a data url from the canvas and then create URIs of the source
|
||||
// and targets
|
||||
let io = Components.classes["@mozilla.org/network/io-service;1"].
|
||||
getService(Components.interfaces.nsIIOService);
|
||||
let source = io.newURI(canvas.toDataURL("image/png"), "UTF8", null);
|
||||
let target = io.newFileURI(file);
|
||||
// prepare to save the canvas data
|
||||
let persist = Components.classes[
|
||||
"@mozilla.org/embedding/browser/nsWebBrowserPersist;1"].
|
||||
createInstance(nsIWebBrowserPersist);
|
||||
persist.persistFlags = nsIWebBrowserPersist.
|
||||
PERSIST_FLAGS_REPLACE_EXISTING_FILES;
|
||||
persist.persistFlags |= nsIWebBrowserPersist.
|
||||
PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
|
||||
|
||||
// prepare to save the canvas data
|
||||
let persist = Components.classes[
|
||||
"@mozilla.org/embedding/browser/nsWebBrowserPersist;1"].
|
||||
createInstance(nsIWebBrowserPersist);
|
||||
persist.persistFlags = nsIWebBrowserPersist.
|
||||
PERSIST_FLAGS_REPLACE_EXISTING_FILES;
|
||||
persist.persistFlags |= nsIWebBrowserPersist.
|
||||
PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
|
||||
// displays a download dialog (remove these 3 lines for silent download)
|
||||
let xfer = Components.classes["@mozilla.org/transfer;1"].
|
||||
createInstance(Components.interfaces.nsITransfer);
|
||||
xfer.init(source, target, "", null, null, null, persist);
|
||||
persist.progressListener = xfer;
|
||||
|
||||
// displays a download dialog (remove these 3 lines for silent download)
|
||||
let xfer = Components.classes["@mozilla.org/transfer;1"].
|
||||
createInstance(Components.interfaces.nsITransfer);
|
||||
xfer.init(source, target, "", null, null, null, persist);
|
||||
persist.progressListener = xfer;
|
||||
// save the canvas data to the file
|
||||
persist.saveURI(source, null, null, null, null, file);
|
||||
}
|
||||
};
|
||||
|
||||
// save the canvas data to the file
|
||||
persist.saveURI(source, null, null, null, null, file);
|
||||
}
|
||||
fp.init(window, null, nsIFilePicker.modeSave);
|
||||
fp.appendFilters(nsIFilePicker.filterImages | nsIFilePicker.filterAll);
|
||||
fp.defaultString = "canvas.png";
|
||||
fp.open(fpCallback);
|
||||
}
|
||||
|
||||
function exportData() {
|
||||
const nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
let filePicker = Components.classes["@mozilla.org/filepicker;1"].
|
||||
createInstance(nsIFilePicker);
|
||||
let eid = getUrlParam("eid");
|
||||
let task = TestPilotSetup.getTaskById(eid);
|
||||
let fp = Components.classes["@mozilla.org/filepicker;1"].
|
||||
createInstance(nsIFilePicker);
|
||||
let fpCallback = function fpCallback_done(aResult) {
|
||||
if (aResult == nsIFilePicker.returnOK ||
|
||||
aResult == nsIFilePicker.returnReplace) {
|
||||
const nsIWebBrowserPersist =
|
||||
Components.interfaces.nsIWebBrowserPersist;
|
||||
let foStream =
|
||||
Components.classes["@mozilla.org/network/file-output-stream;1"].
|
||||
createInstance(Components.interfaces.nsIFileOutputStream);
|
||||
let converter =
|
||||
Components.classes["@mozilla.org/intl/converter-output-stream;1"].
|
||||
createInstance(Components.interfaces.nsIConverterOutputStream);
|
||||
let file = fp.file;
|
||||
let dataStore = task.dataStore;
|
||||
let columnNames = dataStore.getHumanReadableColumnNames();
|
||||
let propertyNames = dataStore.getPropertyNames();
|
||||
let csvString = "";
|
||||
|
||||
filePicker.init(window, null, nsIFilePicker.modeSave);
|
||||
filePicker.appendFilters(
|
||||
nsIFilePicker.filterImages | nsIFilePicker.filterAll);
|
||||
filePicker.defaultString = task.title + ".csv";
|
||||
|
||||
let response = filePicker.show();
|
||||
if (response == nsIFilePicker.returnOK ||
|
||||
response == nsIFilePicker.returnReplace) {
|
||||
const nsIWebBrowserPersist = Components.interfaces.nsIWebBrowserPersist;
|
||||
let foStream =
|
||||
Components.classes["@mozilla.org/network/file-output-stream;1"].
|
||||
createInstance(Components.interfaces.nsIFileOutputStream);
|
||||
let converter =
|
||||
Components.classes["@mozilla.org/intl/converter-output-stream;1"].
|
||||
createInstance(Components.interfaces.nsIConverterOutputStream);
|
||||
let file = filePicker.file;
|
||||
let dataStore = task.dataStore;
|
||||
let columnNames = dataStore.getHumanReadableColumnNames();
|
||||
let propertyNames = dataStore.getPropertyNames();
|
||||
let csvString = "";
|
||||
|
||||
// titles
|
||||
for (let i = 0; i < columnNames.length; i++) {
|
||||
csvString += "\"" + columnNames[i] + "\",";
|
||||
}
|
||||
if (csvString.length > 0) {
|
||||
csvString = csvString.substring(0, (csvString.length - 1));
|
||||
csvString += "\n";
|
||||
}
|
||||
|
||||
dataStore.getAllDataAsJSON(true, function(rawData) {
|
||||
// data
|
||||
for (let i = 0; i < rawData.length; i++) {
|
||||
for (let j = 0; j < columnNames.length; j++) {
|
||||
csvString += "\"" + rawData[i][propertyNames[j]] + "\",";
|
||||
}
|
||||
csvString = csvString.substring(0, (csvString.length - 1));
|
||||
// titles
|
||||
for (let i = 0; i < columnNames.length; i++) {
|
||||
csvString += "\"" + columnNames[i] + "\",";
|
||||
}
|
||||
if (csvString.length > 0) {
|
||||
csvString = csvString.substring(0, (csvString.length - 1));
|
||||
csvString += "\n";
|
||||
}
|
||||
|
||||
// write, create, truncate
|
||||
foStream.init(file, 0x02 | 0x08 | 0x20, 0664, 0);
|
||||
converter.init(foStream, "UTF-8", 0, 0);
|
||||
converter.writeString(csvString);
|
||||
converter.close();
|
||||
});
|
||||
}
|
||||
dataStore.getAllDataAsJSON(true, function(rawData) {
|
||||
// data
|
||||
for (let i = 0; i < rawData.length; i++) {
|
||||
for (let j = 0; j < columnNames.length; j++) {
|
||||
csvString += "\"" + rawData[i][propertyNames[j]] + "\",";
|
||||
}
|
||||
csvString = csvString.substring(0, (csvString.length - 1));
|
||||
csvString += "\n";
|
||||
}
|
||||
|
||||
// write, create, truncate
|
||||
foStream.init(file, 0x02 | 0x08 | 0x20, 0664, 0);
|
||||
converter.init(foStream, "UTF-8", 0, 0);
|
||||
converter.writeString(csvString);
|
||||
converter.close();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
fp.init(window, null, nsIFilePicker.modeSave);
|
||||
fp.appendFilters(nsIFilePicker.filterImages | nsIFilePicker.filterAll);
|
||||
fp.defaultString = task.title + ".csv";
|
||||
fp.open(fpCallback);
|
||||
}
|
||||
|
||||
function openLink(url) {
|
||||
|
|
|
@ -191,7 +191,6 @@ let SocialChatBar = {
|
|||
|
||||
function sizeSocialPanelToContent(iframe) {
|
||||
// FIXME: bug 764787: Maybe we can use nsIDOMWindowUtils.getRootBounds() here?
|
||||
// Need to handle dynamic sizing
|
||||
let doc = iframe.contentDocument;
|
||||
if (!doc) {
|
||||
return;
|
||||
|
@ -199,15 +198,38 @@ function sizeSocialPanelToContent(iframe) {
|
|||
// "notif" is an implementation detail that we should get rid of
|
||||
// eventually
|
||||
let body = doc.getElementById("notif") || doc.body;
|
||||
if (!body || !body.firstChild) {
|
||||
if (!body) {
|
||||
return;
|
||||
}
|
||||
|
||||
let [height, width] = [body.firstChild.offsetHeight || 300, 330];
|
||||
iframe.style.width = width + "px";
|
||||
// XXX - do we want a max for width and height here?
|
||||
// The 300 and 330 defaults also seem arbitrary, so should be revisited.
|
||||
// BUT - for at least one provider, the scrollWidth/offsetWidth/css width
|
||||
// isn't set appropriately, so the 330 is "fixed" for now...
|
||||
iframe.style.width = "330px";
|
||||
// offsetHeight doesn't include margins, so account for that.
|
||||
let cs = doc.defaultView.getComputedStyle(body);
|
||||
let computedHeight = parseInt(cs.marginTop) + body.offsetHeight + parseInt(cs.marginBottom);
|
||||
let height = computedHeight || 300;
|
||||
iframe.style.height = height + "px";
|
||||
}
|
||||
|
||||
function setupDynamicPanelResizer(iframe) {
|
||||
let doc = iframe.contentDocument;
|
||||
let mo = new iframe.contentWindow.MutationObserver(function(mutations) {
|
||||
sizeSocialPanelToContent(iframe);
|
||||
});
|
||||
// Observe anything that causes the size to change.
|
||||
let config = {attributes: true, characterData: true, childList: true, subtree: true};
|
||||
mo.observe(doc, config);
|
||||
doc.addEventListener("unload", function() {
|
||||
if (mo) {
|
||||
mo.disconnect();
|
||||
mo = null;
|
||||
}
|
||||
}, false);
|
||||
sizeSocialPanelToContent(iframe);
|
||||
}
|
||||
|
||||
let SocialFlyout = {
|
||||
get panel() {
|
||||
return document.getElementById("social-flyout-panel");
|
||||
|
@ -235,6 +257,7 @@ let SocialFlyout = {
|
|||
|
||||
unload: function() {
|
||||
let panel = this.panel;
|
||||
panel.hidePopup();
|
||||
if (!panel.firstChild)
|
||||
return
|
||||
panel.removeChild(panel.firstChild);
|
||||
|
@ -275,7 +298,7 @@ let SocialFlyout = {
|
|||
if (src != aURL) {
|
||||
iframe.addEventListener("load", function documentLoaded() {
|
||||
iframe.removeEventListener("load", documentLoaded, true);
|
||||
sizeSocialPanelToContent(iframe);
|
||||
setupDynamicPanelResizer(iframe);
|
||||
if (aCallback) {
|
||||
try {
|
||||
aCallback(iframe.contentWindow);
|
||||
|
@ -332,7 +355,7 @@ let SocialShareButton = {
|
|||
if (profile && profile.displayName) {
|
||||
profileRow.hidden = false;
|
||||
let portrait = document.getElementById("socialUserPortrait");
|
||||
portrait.setAttribute("src", profile.portrait || "chrome://browser/skin/social/social.png");
|
||||
portrait.setAttribute("src", profile.portrait || "chrome://global/skin/icons/information-32.png");
|
||||
let displayName = document.getElementById("socialUserDisplayName");
|
||||
displayName.setAttribute("label", profile.displayName);
|
||||
} else {
|
||||
|
@ -540,7 +563,7 @@ var SocialToolbar = {
|
|||
// response. In that case we'll be called again when it's available, via
|
||||
// social:profile-changed
|
||||
let profile = Social.provider.profile || {};
|
||||
let userPortrait = profile.portrait || "chrome://browser/skin/social/social.png";
|
||||
let userPortrait = profile.portrait || "chrome://global/skin/icons/information-32.png";
|
||||
document.getElementById("social-statusarea-user-portrait").setAttribute("src", userPortrait);
|
||||
|
||||
let notLoggedInLabel = document.getElementById("social-statusarea-notloggedin");
|
||||
|
@ -650,13 +673,13 @@ var SocialToolbar = {
|
|||
notificationFrame.docShell.isActive = true;
|
||||
notificationFrame.docShell.isAppTab = true;
|
||||
if (notificationFrame.contentDocument.readyState == "complete") {
|
||||
sizeSocialPanelToContent(notificationFrame);
|
||||
setupDynamicPanelResizer(notificationFrame);
|
||||
dispatchPanelEvent("socialFrameShow");
|
||||
} else {
|
||||
// first time load, wait for load and dispatch after load
|
||||
notificationFrame.addEventListener("load", function panelBrowserOnload(e) {
|
||||
notificationFrame.removeEventListener("load", panelBrowserOnload, true);
|
||||
sizeSocialPanelToContent(notificationFrame);
|
||||
setupDynamicPanelResizer(notificationFrame);
|
||||
setTimeout(function() {
|
||||
dispatchPanelEvent("socialFrameShow");
|
||||
}, 0);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<binding id="chatbox">
|
||||
<content orient="vertical" mousethrough="never">
|
||||
<xul:hbox class="chat-titlebar" xbl:inherits="minimized,selected"
|
||||
onclick="document.getBindingParent(this).toggle();">
|
||||
onclick="document.getBindingParent(this).toggle();" align="baseline">
|
||||
<xul:image class="chat-status-icon" xbl:inherits="src=image"/>
|
||||
<xul:label class="chat-title" flex="1" xbl:inherits="value=label,crop"/>
|
||||
<xul:toolbarbutton class="chat-close-button chat-toolbarbutton"
|
||||
|
|
|
@ -115,5 +115,24 @@ var tests = {
|
|||
}
|
||||
}
|
||||
port.postMessage({topic: "test-worker-chat", data: chatUrl});
|
||||
},
|
||||
testCloseOnLogout: function(next) {
|
||||
const chatUrl = "https://example.com/browser/browser/base/content/test/social_chat.html";
|
||||
let port = Social.provider.getWorkerPort();
|
||||
ok(port, "provider has a port");
|
||||
port.postMessage({topic: "test-init"});
|
||||
port.onmessage = function (e) {
|
||||
let topic = e.data.topic;
|
||||
switch (topic) {
|
||||
case "got-chatbox-message":
|
||||
ok(true, "got a chat window opened");
|
||||
port.postMessage({topic: "test-logout"});
|
||||
waitForCondition(function() document.getElementById("pinnedchats").firstChild == null,
|
||||
next,
|
||||
"chat windows didn't close");
|
||||
break;
|
||||
}
|
||||
}
|
||||
port.postMessage({topic: "test-worker-chat", data: chatUrl});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,11 +31,12 @@ var tests = {
|
|||
case "got-flyout-visibility":
|
||||
if (e.data.result == "hidden") {
|
||||
ok(true, "flyout visibility is 'hidden'");
|
||||
is(panel.state, "closed", "panel really is closed");
|
||||
port.close();
|
||||
next();
|
||||
} else if (e.data.result == "shown") {
|
||||
ok(true, "flyout visibility is 'shown");
|
||||
panel.hidePopup();
|
||||
port.postMessage({topic: "test-flyout-close"});
|
||||
}
|
||||
break;
|
||||
case "got-flyout-message":
|
||||
|
@ -44,6 +45,35 @@ var tests = {
|
|||
}
|
||||
}
|
||||
port.postMessage({topic: "test-init"});
|
||||
},
|
||||
|
||||
testResizeFlyout: function(next) {
|
||||
let panel = document.getElementById("social-flyout-panel");
|
||||
let port = Social.provider.getWorkerPort();
|
||||
ok(port, "provider has a port");
|
||||
port.onmessage = function (e) {
|
||||
let topic = e.data.topic;
|
||||
switch (topic) {
|
||||
case "test-init-done":
|
||||
port.postMessage({topic: "test-flyout-open"});
|
||||
break;
|
||||
case "got-flyout-visibility":
|
||||
// The width of the flyout should be 250px
|
||||
let iframe = panel.firstChild;
|
||||
let cs = iframe.contentWindow.getComputedStyle(iframe.contentDocument.body);
|
||||
is(cs.width, "250px", "should be 250px wide");
|
||||
iframe.contentDocument.addEventListener("SocialTest-DoneMakeWider", function _doneHandler() {
|
||||
iframe.contentDocument.removeEventListener("SocialTest-DoneMakeWider", _doneHandler, false);
|
||||
cs = iframe.contentWindow.getComputedStyle(iframe.contentDocument.body);
|
||||
is(cs.width, "500px", "should now be 500px wide");
|
||||
panel.hidePopup();
|
||||
next();
|
||||
}, false);
|
||||
SocialFlyout.dispatchPanelEvent("socialTest-MakeWider");
|
||||
break;
|
||||
}
|
||||
}
|
||||
port.postMessage({topic: "test-init"});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -56,8 +56,6 @@ var tests = {
|
|||
testProfileUnset: function(next) {
|
||||
Social.provider.updateUserProfile({});
|
||||
// check dom values
|
||||
let portrait = document.getElementById("social-statusarea-user-portrait").getAttribute("src");
|
||||
is(portrait, "chrome://browser/skin/social/social.png", "portrait is generic");
|
||||
let userButton = document.getElementById("social-statusarea-username");
|
||||
ok(userButton.hidden, "username is not visible");
|
||||
let ambience = document.getElementById("social-status-iconbox").firstChild;
|
||||
|
|
|
@ -14,9 +14,16 @@
|
|||
var port = navigator.mozSocial.getWorker().port;
|
||||
port.postMessage({topic: "flyout-visibility", result: "hidden"});
|
||||
}, false);
|
||||
window.addEventListener("socialTest-MakeWider", function(e) {
|
||||
document.body.setAttribute("style", "width: 500px;");
|
||||
document.body.offsetWidth; // force a layout flush
|
||||
var evt = document.createEvent("CustomEvent");
|
||||
evt.initCustomEvent("SocialTest-DoneMakeWider", true, true, {});
|
||||
document.documentElement.dispatchEvent(evt);
|
||||
}, false);
|
||||
</script>
|
||||
</head>
|
||||
<body onload="pingWorker();">
|
||||
<body style="max-width: 250px;" onload="pingWorker();">
|
||||
<p>This is a test social flyout panel.</p>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
case "test-flyout-open":
|
||||
navigator.mozSocial.openPanel("social_flyout.html");
|
||||
break;
|
||||
case "test-flyout-close":
|
||||
navigator.mozSocial.closePanel();
|
||||
break;
|
||||
case "test-chatbox-open":
|
||||
var url = "social_chat.html";
|
||||
var data = e.data.data;
|
||||
|
|
|
@ -13,6 +13,9 @@ onconnect = function(e) {
|
|||
testPort = port;
|
||||
port.postMessage({topic: "test-init-done"});
|
||||
break;
|
||||
case "test-logout":
|
||||
apiPort.postMessage({topic: "social.user-profile", data: {}});
|
||||
break;
|
||||
case "sidebar-message":
|
||||
sidebarPort = port;
|
||||
if (testPort && event.data.result == "ok")
|
||||
|
@ -64,6 +67,9 @@ onconnect = function(e) {
|
|||
case "flyout-visibility":
|
||||
testPort.postMessage({topic:"got-flyout-visibility", result: event.data.result});
|
||||
break;
|
||||
case "test-flyout-close":
|
||||
sidebarPort.postMessage({topic:"test-flyout-close"});
|
||||
break;
|
||||
case "test-worker-chat":
|
||||
apiPort.postMessage({topic: "social.request-chat", data: event.data.data });
|
||||
break;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
This is the pdf.js project output, https://github.com/mozilla/pdf.js
|
||||
|
||||
Current extension version is: 0.5.22
|
||||
Current extension version is: 0.5.184
|
||||
|
||||
|
|
|
@ -539,8 +539,8 @@ PdfStreamConverter.prototype = {
|
|||
.getService(Ci.nsIScriptSecurityManager);
|
||||
var uri = ioService.newURI(PDF_VIEWER_WEB_PAGE, null, null);
|
||||
// FF16 and below had getCodebasePrincipal (bug 774585)
|
||||
var resourcePrincipal = 'getSimpleCodebasePrincipal' in securityManager ?
|
||||
securityManager.getSimpleCodebasePrincipal(uri) :
|
||||
var resourcePrincipal = 'getNoAppCodebasePrincipal' in securityManager ?
|
||||
securityManager.getNoAppCodebasePrincipal(uri) :
|
||||
securityManager.getCodebasePrincipal(uri);
|
||||
channel.owner = resourcePrincipal;
|
||||
}
|
||||
|
|
|
@ -121,7 +121,7 @@ html[dir='rtl'] .innerCenter {
|
|||
-o-transition-timing-function: ease;
|
||||
transition-duration: 200ms;
|
||||
transition-timing-function: ease;
|
||||
|
||||
|
||||
}
|
||||
html[dir='ltr'] #sidebarContainer {
|
||||
-webkit-transition-property: left;
|
||||
|
@ -629,7 +629,7 @@ html[dir='rtl'] .toolbarButton:first-child {
|
|||
display: inline-block;
|
||||
content: url(images/toolbarButton-sidebarToggle.png);
|
||||
}
|
||||
|
||||
|
||||
html[dir='ltr'] .toolbarButton.pageUp::before {
|
||||
display: inline-block;
|
||||
content: url(images/toolbarButton-pageUp.png);
|
||||
|
@ -639,7 +639,7 @@ html[dir='rtl'] .toolbarButton.pageUp::before {
|
|||
display: inline-block;
|
||||
content: url(images/toolbarButton-pageUp-rtl.png);
|
||||
}
|
||||
|
||||
|
||||
html[dir='ltr'] .toolbarButton.pageDown::before {
|
||||
display: inline-block;
|
||||
content: url(images/toolbarButton-pageDown.png);
|
||||
|
@ -654,7 +654,7 @@ html[dir='rtl'] .toolbarButton.pageDown::before {
|
|||
display: inline-block;
|
||||
content: url(images/toolbarButton-zoomOut.png);
|
||||
}
|
||||
|
||||
|
||||
.toolbarButton.zoomIn::before {
|
||||
display: inline-block;
|
||||
content: url(images/toolbarButton-zoomIn.png);
|
||||
|
@ -691,12 +691,12 @@ html[dir='rtl'] .toolbarButton.pageDown::before {
|
|||
.toolbarButton.bookmark::before {
|
||||
content: url(images/toolbarButton-bookmark.png);
|
||||
}
|
||||
|
||||
|
||||
#viewThumbnail.toolbarButton::before {
|
||||
display: inline-block;
|
||||
content: url(images/toolbarButton-viewThumbnail.png);
|
||||
}
|
||||
|
||||
|
||||
#viewOutline.toolbarButton::before {
|
||||
display: inline-block;
|
||||
content: url(images/toolbarButton-viewOutline.png);
|
||||
|
@ -797,7 +797,7 @@ html[dir='rtl'] .toolbarButton.pageDown::before {
|
|||
padding: 7px;
|
||||
-moz-transition-duration: 150ms;
|
||||
}
|
||||
|
||||
|
||||
a:focus > .thumbnail > .thumbnailSelectionRing > .thumbnailImage,
|
||||
.thumbnail:hover > .thumbnailSelectionRing > .thumbnailImage {
|
||||
opacity: .9;
|
||||
|
@ -1016,7 +1016,7 @@ canvas {
|
|||
background: -moz-linear-gradient(top, #b2b2b2 0%,#898989 100%);
|
||||
background: -ms-linear-gradient(top, #b2b2b2 0%,#898989 100%);
|
||||
background: -o-linear-gradient(top, #b2b2b2 0%,#898989 100%);
|
||||
background: linear-gradient(top, #b2b2b2 0%,#898989 100%);
|
||||
background: linear-gradient(top, #b2b2b2 0%,#898989 100%);
|
||||
|
||||
border-top-left-radius: 2px;
|
||||
border-bottom-left-radius: 2px;
|
||||
|
@ -1066,6 +1066,7 @@ canvas {
|
|||
color: transparent;
|
||||
position: absolute;
|
||||
line-height:1.3;
|
||||
white-space:pre;
|
||||
}
|
||||
|
||||
/* TODO: file FF bug to support ::-moz-selection:window-inactive
|
||||
|
@ -1202,7 +1203,7 @@ canvas {
|
|||
|
||||
@page {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#printContainer {
|
||||
display: none;
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -35,7 +35,6 @@ var RenderingStates = {
|
|||
FINISHED: 3
|
||||
};
|
||||
|
||||
PDFJS.workerSrc = '../build/pdf.js';
|
||||
|
||||
var mozL10n = document.mozL10n || document.webL10n;
|
||||
|
||||
|
@ -286,9 +285,11 @@ var PDFView = {
|
|||
isFullscreen: false,
|
||||
previousScale: null,
|
||||
pageRotation: 0,
|
||||
lastScroll: 0,
|
||||
|
||||
// called once when the document is loaded
|
||||
initialize: function pdfViewInitialize() {
|
||||
var self = this;
|
||||
var container = this.container = document.getElementById('viewerContainer');
|
||||
this.pageViewScroll = {};
|
||||
this.watchScroll(container, this.pageViewScroll, updateViewarea);
|
||||
|
@ -300,6 +301,9 @@ var PDFView = {
|
|||
this.renderHighestPriority.bind(this));
|
||||
|
||||
this.initialized = true;
|
||||
container.addEventListener('scroll', function() {
|
||||
self.lastScroll = Date.now();
|
||||
}, false);
|
||||
},
|
||||
|
||||
// Helper function to keep track whether a div was scrolled up or down and
|
||||
|
@ -437,7 +441,7 @@ var PDFView = {
|
|||
|
||||
get supportsFullscreen() {
|
||||
var doc = document.documentElement;
|
||||
var support = doc.requestFullScreen || doc.mozRequestFullScreen ||
|
||||
var support = doc.requestFullscreen || doc.mozRequestFullScreen ||
|
||||
doc.webkitRequestFullScreen;
|
||||
Object.defineProperty(this, 'supportsFullScreen', { value: support,
|
||||
enumerable: true,
|
||||
|
@ -537,7 +541,6 @@ var PDFView = {
|
|||
function noData() {
|
||||
FirefoxCom.request('download', { originalUrl: url });
|
||||
}
|
||||
|
||||
var url = this.url.split('#')[0];
|
||||
// Document isn't ready just try to download with the url.
|
||||
if (!this.pdfDocument) {
|
||||
|
@ -546,10 +549,8 @@ var PDFView = {
|
|||
}
|
||||
this.pdfDocument.getData().then(
|
||||
function getDataSuccess(data) {
|
||||
var bb = new MozBlobBuilder();
|
||||
bb.append(data.buffer);
|
||||
var blobUrl = window.URL.createObjectURL(
|
||||
bb.getBlob('application/pdf'));
|
||||
var blob = PDFJS.createBlob(data.buffer, 'application/pdf');
|
||||
var blobUrl = window.URL.createObjectURL(blob);
|
||||
|
||||
FirefoxCom.request('download', { blobUrl: blobUrl, originalUrl: url },
|
||||
function response(err) {
|
||||
|
@ -1052,7 +1053,7 @@ var PDFView = {
|
|||
function extractPageText(pageIndex) {
|
||||
self.pages[pageIndex].pdfPage.getTextContent().then(
|
||||
function textContentResolved(textContent) {
|
||||
self.pageText[pageIndex] = textContent;
|
||||
self.pageText[pageIndex] = textContent.join('');
|
||||
self.search();
|
||||
if ((pageIndex + 1) < self.pages.length)
|
||||
extractPageText(pageIndex + 1);
|
||||
|
@ -1164,7 +1165,7 @@ var PDFView = {
|
|||
},
|
||||
|
||||
fullscreen: function pdfViewFullscreen() {
|
||||
var isFullscreen = document.fullscreen || document.mozFullScreen ||
|
||||
var isFullscreen = document.fullscreenElement || document.mozFullScreen ||
|
||||
document.webkitIsFullScreen;
|
||||
|
||||
if (isFullscreen) {
|
||||
|
@ -1172,8 +1173,8 @@ var PDFView = {
|
|||
}
|
||||
|
||||
var wrapper = document.getElementById('viewerContainer');
|
||||
if (document.documentElement.requestFullScreen) {
|
||||
wrapper.requestFullScreen();
|
||||
if (document.documentElement.requestFullscreen) {
|
||||
wrapper.requestFullscreen();
|
||||
} else if (document.documentElement.mozRequestFullScreen) {
|
||||
wrapper.mozRequestFullScreen();
|
||||
} else if (document.documentElement.webkitRequestFullScreen) {
|
||||
|
@ -1217,9 +1218,7 @@ var PDFView = {
|
|||
|
||||
var currentPage = this.pages[this.page - 1];
|
||||
|
||||
if (this.isFullscreen) {
|
||||
this.parseScale('page-fit', true);
|
||||
}
|
||||
this.parseScale(this.currentScaleValue, true);
|
||||
|
||||
this.renderHighestPriority();
|
||||
|
||||
|
@ -1242,6 +1241,8 @@ var PageView = function pageView(container, pdfPage, id, scale,
|
|||
this.renderingState = RenderingStates.INITIAL;
|
||||
this.resume = null;
|
||||
|
||||
this.textContent = null;
|
||||
|
||||
var anchor = document.createElement('a');
|
||||
anchor.name = '' + this.id;
|
||||
|
||||
|
@ -1462,6 +1463,13 @@ var PageView = function pageView(container, pdfPage, id, scale,
|
|||
}, 0);
|
||||
};
|
||||
|
||||
this.getTextContent = function pageviewGetTextContent() {
|
||||
if (!this.textContent) {
|
||||
this.textContent = this.pdfPage.getTextContent();
|
||||
}
|
||||
return this.textContent;
|
||||
};
|
||||
|
||||
this.draw = function pageviewDraw(callback) {
|
||||
if (this.renderingState !== RenderingStates.INITIAL)
|
||||
error('Must be in new state before drawing');
|
||||
|
@ -1542,6 +1550,14 @@ var PageView = function pageView(container, pdfPage, id, scale,
|
|||
}
|
||||
);
|
||||
|
||||
if (textLayer) {
|
||||
this.getTextContent().then(
|
||||
function textContentResolved(textContent) {
|
||||
textLayer.setTextContent(textContent);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
setupAnnotations(this.pdfPage, this.viewport);
|
||||
div.setAttribute('data-loaded', true);
|
||||
};
|
||||
|
@ -1832,7 +1848,10 @@ var CustomStyle = (function CustomStyleClosure() {
|
|||
})();
|
||||
|
||||
var TextLayerBuilder = function textLayerBuilder(textLayerDiv) {
|
||||
var textLayerFrag = document.createDocumentFragment();
|
||||
this.textLayerDiv = textLayerDiv;
|
||||
this.layoutDone = false;
|
||||
this.divContentDone = false;
|
||||
|
||||
this.beginLayout = function textLayerBuilderBeginLayout() {
|
||||
this.textDivs = [];
|
||||
|
@ -1840,84 +1859,104 @@ var TextLayerBuilder = function textLayerBuilder(textLayerDiv) {
|
|||
};
|
||||
|
||||
this.endLayout = function textLayerBuilderEndLayout() {
|
||||
this.layoutDone = true;
|
||||
this.insertDivContent();
|
||||
},
|
||||
|
||||
this.renderLayer = function textLayerBuilderRenderLayer() {
|
||||
var self = this;
|
||||
var textDivs = this.textDivs;
|
||||
var textLayerDiv = this.textLayerDiv;
|
||||
var renderTimer = null;
|
||||
var renderingDone = false;
|
||||
var renderInterval = 0;
|
||||
var resumeInterval = 500; // in ms
|
||||
|
||||
var canvas = document.createElement('canvas');
|
||||
var ctx = canvas.getContext('2d');
|
||||
|
||||
// Render the text layer, one div at a time
|
||||
function renderTextLayer() {
|
||||
if (textDivs.length === 0) {
|
||||
clearInterval(renderTimer);
|
||||
renderingDone = true;
|
||||
self.textLayerDiv = textLayerDiv = canvas = ctx = null;
|
||||
return;
|
||||
}
|
||||
// No point in rendering so many divs as it'd make the browser unusable
|
||||
// even after the divs are rendered
|
||||
if (textDivs.length > 100000)
|
||||
return;
|
||||
|
||||
while (textDivs.length > 0) {
|
||||
var textDiv = textDivs.shift();
|
||||
if (textDiv.dataset.textLength > 0) {
|
||||
textLayerDiv.appendChild(textDiv);
|
||||
textLayerFrag.appendChild(textDiv);
|
||||
|
||||
if (textDiv.dataset.textLength > 1) { // avoid div by zero
|
||||
// Adjust div width to match canvas text
|
||||
ctx.font = textDiv.style.fontSize + ' ' + textDiv.style.fontFamily;
|
||||
var width = ctx.measureText(textDiv.textContent).width;
|
||||
|
||||
ctx.font = textDiv.style.fontSize + ' sans-serif';
|
||||
var width = ctx.measureText(textDiv.textContent).width;
|
||||
if (width > 0) {
|
||||
var textScale = textDiv.dataset.canvasWidth / width;
|
||||
|
||||
var textScale = textDiv.dataset.canvasWidth / width;
|
||||
|
||||
CustomStyle.setProp('transform' , textDiv,
|
||||
'scale(' + textScale + ', 1)');
|
||||
CustomStyle.setProp('transformOrigin' , textDiv, '0% 0%');
|
||||
}
|
||||
} // textLength > 0
|
||||
}
|
||||
renderTimer = setInterval(renderTextLayer, renderInterval);
|
||||
|
||||
// Stop rendering when user scrolls. Resume after XXX milliseconds
|
||||
// of no scroll events
|
||||
var scrollTimer = null;
|
||||
function textLayerOnScroll() {
|
||||
if (renderingDone) {
|
||||
window.removeEventListener('scroll', textLayerOnScroll, false);
|
||||
return;
|
||||
CustomStyle.setProp('transform' , textDiv,
|
||||
'scale(' + textScale + ', 1)');
|
||||
CustomStyle.setProp('transformOrigin' , textDiv, '0% 0%');
|
||||
}
|
||||
}
|
||||
|
||||
// Immediately pause rendering
|
||||
clearInterval(renderTimer);
|
||||
textLayerDiv.appendChild(textLayerFrag);
|
||||
};
|
||||
|
||||
clearTimeout(scrollTimer);
|
||||
scrollTimer = setTimeout(function textLayerScrollTimer() {
|
||||
// Resume rendering
|
||||
renderTimer = setInterval(renderTextLayer, renderInterval);
|
||||
}, resumeInterval);
|
||||
} // textLayerOnScroll
|
||||
this.setupRenderLayoutTimer = function textLayerSetupRenderLayoutTimer() {
|
||||
// Schedule renderLayout() if user has been scrolling, otherwise
|
||||
// run it right away
|
||||
var kRenderDelay = 200; // in ms
|
||||
var self = this;
|
||||
if (Date.now() - PDFView.lastScroll > kRenderDelay) {
|
||||
// Render right away
|
||||
this.renderLayer();
|
||||
} else {
|
||||
// Schedule
|
||||
if (this.renderTimer)
|
||||
clearTimeout(this.renderTimer);
|
||||
this.renderTimer = setTimeout(function() {
|
||||
self.setupRenderLayoutTimer();
|
||||
}, kRenderDelay);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('scroll', textLayerOnScroll, false);
|
||||
}; // endLayout
|
||||
|
||||
this.appendText = function textLayerBuilderAppendText(text,
|
||||
fontName, fontSize) {
|
||||
this.appendText = function textLayerBuilderAppendText(fontName, fontSize,
|
||||
geom) {
|
||||
var textDiv = document.createElement('div');
|
||||
|
||||
// vScale and hScale already contain the scaling to pixel units
|
||||
var fontHeight = fontSize * text.geom.vScale;
|
||||
textDiv.dataset.canvasWidth = text.canvasWidth * text.geom.hScale;
|
||||
var fontHeight = fontSize * geom.vScale;
|
||||
textDiv.dataset.canvasWidth = geom.canvasWidth * geom.hScale;
|
||||
textDiv.dataset.fontName = fontName;
|
||||
|
||||
textDiv.style.fontSize = fontHeight + 'px';
|
||||
textDiv.style.left = text.geom.x + 'px';
|
||||
textDiv.style.top = (text.geom.y - fontHeight) + 'px';
|
||||
textDiv.textContent = PDFJS.bidi(text, -1);
|
||||
textDiv.dir = text.direction;
|
||||
textDiv.dataset.textLength = text.length;
|
||||
textDiv.style.fontFamily = fontName;
|
||||
textDiv.style.left = geom.x + 'px';
|
||||
textDiv.style.top = (geom.y - fontHeight) + 'px';
|
||||
|
||||
// The content of the div is set in the `setTextContent` function.
|
||||
|
||||
this.textDivs.push(textDiv);
|
||||
};
|
||||
|
||||
this.insertDivContent = function textLayerUpdateTextContent() {
|
||||
// Only set the content of the divs once layout has finished, the content
|
||||
// for the divs is available and content is not yet set on the divs.
|
||||
if (!this.layoutDone || this.divContentDone || !this.textContent)
|
||||
return;
|
||||
|
||||
this.divContentDone = true;
|
||||
|
||||
var textDivs = this.textDivs;
|
||||
var bidiTexts = this.textContent.bidiTexts;
|
||||
|
||||
for (var i = 0; i < bidiTexts.length; i++) {
|
||||
var bidiText = bidiTexts[i];
|
||||
var textDiv = textDivs[i];
|
||||
|
||||
textDiv.textContent = bidiText.str;
|
||||
textDiv.dir = bidiText.ltr ? 'ltr' : 'rtl';
|
||||
}
|
||||
|
||||
this.setupRenderLayoutTimer();
|
||||
};
|
||||
|
||||
this.setTextContent = function textLayerBuilderSetTextContent(textContent) {
|
||||
this.textContent = textContent;
|
||||
this.insertDivContent();
|
||||
};
|
||||
};
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function webViewerLoad(evt) {
|
||||
|
@ -2059,7 +2098,7 @@ document.addEventListener('DOMContentLoaded', function webViewerLoad(evt) {
|
|||
});
|
||||
|
||||
document.getElementById('searchTermsInput').addEventListener('keydown',
|
||||
function() {
|
||||
function(event) {
|
||||
if (event.keyCode == 13) {
|
||||
PDFView.search();
|
||||
}
|
||||
|
@ -2282,6 +2321,7 @@ window.addEventListener('keydown', function keydown(evt) {
|
|||
PDFView.zoomIn();
|
||||
handled = true;
|
||||
break;
|
||||
case 173: // FF/Mac '-'
|
||||
case 109: // FF '-'
|
||||
case 189: // Chrome '-'
|
||||
PDFView.zoomOut();
|
||||
|
@ -2362,7 +2402,7 @@ window.addEventListener('afterprint', function afterPrint(evt) {
|
|||
|
||||
(function fullscreenClosure() {
|
||||
function fullscreenChange(e) {
|
||||
var isFullscreen = document.fullscreen || document.mozFullScreen ||
|
||||
var isFullscreen = document.fullscreenElement || document.mozFullScreen ||
|
||||
document.webkitIsFullScreen;
|
||||
|
||||
if (!isFullscreen) {
|
||||
|
|
|
@ -398,17 +398,18 @@ social.error.closeSidebar.accesskey=C
|
|||
# Identity notifications popups
|
||||
identity.termsOfService = Terms of Service
|
||||
identity.privacyPolicy = Privacy Policy
|
||||
# LOCALIZATION NOTE (identity.chooseIdentity.description): %S is the website origin (e.g. https://www.mozilla.org) shown in popup notifications.
|
||||
identity.chooseIdentity.description = Sign in to %S
|
||||
identity.chooseIdentity.label = Use an existing email
|
||||
identity.newIdentity.label = Use a different email
|
||||
identity.newIdentity.accessKey = e
|
||||
identity.newIdentity.email.placeholder = Email
|
||||
# LOCALIZATION NOTE (identity.newIdentity.description, identity.chooseIdentity.description): %S is the website origin (ie. https://www.mozilla.org) shown in popup notifications.
|
||||
# LOCALIZATION NOTE (identity.newIdentity.description): %S is the website origin (e.g. https://www.mozilla.org) shown in popup notifications.
|
||||
identity.newIdentity.description = Enter your email address to sign in to %S
|
||||
identity.next.label = Next
|
||||
identity.next.accessKey = n
|
||||
# LOCALIZATION NOTE: shown in the popup notification when a user successfully logs into a website
|
||||
# LOCALIZATION NOTE (identity.loggedIn.description): %S is the website origin (ie. https://www.mozilla.org)
|
||||
# LOCALIZATION NOTE (identity.loggedIn.description): %S is the user's identity (e.g. user@example.com)
|
||||
identity.loggedIn.description = Signed in as: %S
|
||||
identity.loggedIn.signOut.label = Sign Out
|
||||
identity.loggedIn.signOut.accessKey = O
|
||||
|
|
|
@ -18,8 +18,8 @@ zoom_in_label=Zoom In
|
|||
zoom.title=Zoom
|
||||
print.title=Print
|
||||
print_label=Print
|
||||
fullscreen.title=Fullscreen
|
||||
fullscreen_label=Fullscreen
|
||||
presentation_mode.title=Switch to Presentation Mode
|
||||
presentation_mode_label=Presentation Mode
|
||||
open_file.title=Open File
|
||||
open_file_label=Open
|
||||
download.title=Download
|
||||
|
@ -51,8 +51,8 @@ thumb_page_title=Page {{page}}
|
|||
thumb_page_canvas=Thumbnail of Page {{page}}
|
||||
|
||||
# Context menu
|
||||
page_rotate_cw=Rotate Clockwise
|
||||
page_rotate_ccw=Rotate Counter-Clockwise
|
||||
page_rotate_cw.label=Rotate Clockwise
|
||||
page_rotate_ccw.label=Rotate Counter-Clockwise
|
||||
|
||||
# Search panel button title and messages
|
||||
search=Find
|
||||
|
|
|
@ -2702,7 +2702,6 @@ html|*#gcli-output-frame {
|
|||
height: 32px;
|
||||
border-radius: 2px;
|
||||
margin: 10px;
|
||||
list-style-image: url("chrome://browser/skin/social/social.png");
|
||||
}
|
||||
|
||||
#social-statusarea-username {
|
||||
|
@ -2713,6 +2712,7 @@ html|*#gcli-output-frame {
|
|||
cursor: pointer;
|
||||
min-width: 0;
|
||||
margin: 0 6px;
|
||||
list-style-image: none;
|
||||
}
|
||||
#social-statusarea-username:hover {
|
||||
text-decoration: underline;
|
||||
|
@ -2766,6 +2766,7 @@ html|*#gcli-output-frame {
|
|||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 2px;
|
||||
-moz-padding-start: 6px;
|
||||
border: none;
|
||||
border-bottom: 1px solid gray;
|
||||
cursor: pointer;
|
||||
|
|
|
@ -3382,7 +3382,6 @@ html|*#gcli-output-frame {
|
|||
width: 32px;
|
||||
height: 32px;
|
||||
margin: 10px;
|
||||
list-style-image: url("chrome://browser/skin/social/social.png");
|
||||
}
|
||||
|
||||
#social-statusarea-username {
|
||||
|
@ -3391,6 +3390,7 @@ html|*#gcli-output-frame {
|
|||
cursor: pointer;
|
||||
min-width: 0;
|
||||
margin: 0 6px;
|
||||
list-style-image: none;
|
||||
}
|
||||
|
||||
#social-statusarea-username:hover {
|
||||
|
@ -3452,6 +3452,7 @@ html|*#gcli-output-frame {
|
|||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 2px;
|
||||
-moz-padding-start: 6px;
|
||||
border: none;
|
||||
border-bottom: 1px solid #404040;
|
||||
cursor: pointer;
|
||||
|
|
|
@ -83,7 +83,6 @@ browser.jar:
|
|||
skin/classic/browser/places/minus-active.png (places/minus-active.png)
|
||||
skin/classic/browser/places/plus.png (places/plus.png)
|
||||
skin/classic/browser/places/plus-active.png (places/plus-active.png)
|
||||
skin/classic/browser/places/starPage.png (places/starPage.png)
|
||||
skin/classic/browser/places/starred48.png (places/starred48.png)
|
||||
skin/classic/browser/places/unstarred48.png (places/unstarred48.png)
|
||||
skin/classic/browser/places/unfiledBookmarks.png (places/unfiledBookmarks.png)
|
||||
|
|
Двоичные данные
browser/themes/pinstripe/places/starPage.png
Двоичные данные
browser/themes/pinstripe/places/starPage.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 653 B |
|
@ -3401,7 +3401,6 @@ html|*#gcli-output-frame {
|
|||
height: 32px;
|
||||
border-radius: 2px;
|
||||
margin: 10px;
|
||||
list-style-image: url("chrome://browser/skin/social/social.png");
|
||||
}
|
||||
|
||||
#social-statusarea-username {
|
||||
|
@ -3412,6 +3411,7 @@ html|*#gcli-output-frame {
|
|||
cursor: pointer;
|
||||
min-width: 0;
|
||||
margin: 0 6px;
|
||||
list-style-image: none;
|
||||
}
|
||||
#social-statusarea-username:hover {
|
||||
text-decoration: underline;
|
||||
|
@ -3470,6 +3470,7 @@ html|*#gcli-output-frame {
|
|||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 2px;
|
||||
-moz-padding-start: 6px;
|
||||
border: none;
|
||||
border-bottom: 1px solid gray;
|
||||
cursor: pointer;
|
||||
|
|
|
@ -29,6 +29,12 @@ _DEFAULT_HTTP_PORT = 8888
|
|||
_DEFAULT_SSL_PORT = 4443
|
||||
_DEFAULT_WEBSOCKET_PORT = 9988
|
||||
|
||||
# from nsIPrincipal.idl
|
||||
_APP_STATUS_NOT_INSTALLED = 0
|
||||
_APP_STATUS_INSTALLED = 1
|
||||
_APP_STATUS_PRIVILEGED = 2
|
||||
_APP_STATUS_CERTIFIED = 3
|
||||
|
||||
#expand _DIST_BIN = __XPC_BIN_PATH__
|
||||
#expand _IS_WIN32 = len("__WIN32__") != 0
|
||||
#expand _IS_MAC = __IS_MAC__ != 0
|
||||
|
@ -297,7 +303,8 @@ class Automation(object):
|
|||
"receipt": null,
|
||||
"installTime": 132333986000,
|
||||
"manifestURL": "$manifestURL",
|
||||
"localId": $localId
|
||||
"localId": $localId,
|
||||
"appStatus": $appStatus
|
||||
}""")
|
||||
|
||||
manifestTemplate = Template("""{
|
||||
|
@ -520,31 +527,50 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t
|
|||
'name': 'http_example_org',
|
||||
'origin': 'http://example.org',
|
||||
'manifestURL': 'http://example.org/manifest.webapp',
|
||||
'description': 'http://example.org App'
|
||||
'description': 'http://example.org App',
|
||||
'appStatus': _APP_STATUS_INSTALLED
|
||||
},
|
||||
{
|
||||
'name': 'https_example_com',
|
||||
'origin': 'https://example.com',
|
||||
'manifestURL': 'https://example.com/manifest.webapp',
|
||||
'description': 'https://example.com App'
|
||||
'description': 'https://example.com App',
|
||||
'appStatus': _APP_STATUS_INSTALLED
|
||||
},
|
||||
{
|
||||
'name': 'http_test1_example_org',
|
||||
'origin': 'http://test1.example.org',
|
||||
'manifestURL': 'http://test1.example.org/manifest.webapp',
|
||||
'description': 'http://test1.example.org App'
|
||||
'description': 'http://test1.example.org App',
|
||||
'appStatus': _APP_STATUS_INSTALLED
|
||||
},
|
||||
{
|
||||
'name': 'http_test1_example_org_8000',
|
||||
'origin': 'http://test1.example.org:8000',
|
||||
'manifestURL': 'http://test1.example.org:8000/manifest.webapp',
|
||||
'description': 'http://test1.example.org:8000 App'
|
||||
'description': 'http://test1.example.org:8000 App',
|
||||
'appStatus': _APP_STATUS_INSTALLED
|
||||
},
|
||||
{
|
||||
'name': 'http_sub1_test1_example_org',
|
||||
'origin': 'http://sub1.test1.example.org',
|
||||
'manifestURL': 'http://sub1.test1.example.org/manifest.webapp',
|
||||
'description': 'http://sub1.test1.example.org App'
|
||||
'description': 'http://sub1.test1.example.org App',
|
||||
'appStatus': _APP_STATUS_INSTALLED
|
||||
},
|
||||
{
|
||||
'name': 'https_example_com_privileged',
|
||||
'origin': 'https://example.com',
|
||||
'manifestURL': 'https://example.com/manifest_priv.webapp',
|
||||
'description': 'https://example.com Privileged App',
|
||||
'appStatus': _APP_STATUS_PRIVILEGED
|
||||
},
|
||||
{
|
||||
'name': 'https_example_com_certified',
|
||||
'origin': 'https://example.com',
|
||||
'manifestURL': 'https://example.com/manifest_cert.webapp',
|
||||
'description': 'https://example.com Certified App',
|
||||
'appStatus': _APP_STATUS_CERTIFIED
|
||||
},
|
||||
];
|
||||
self.setupTestApps(profileDir, apps)
|
||||
|
|
|
@ -46,7 +46,5 @@ if __name__ == '__main__':
|
|||
url = "http://localhost:%d/bloatcycle.html" % PORT
|
||||
appPath = os.path.join(SCRIPT_DIR, automation.DEFAULT_APP)
|
||||
status = automation.runApp(url, browserEnv, appPath, PROFILE_DIRECTORY,
|
||||
# leaktest builds are slow, give up and
|
||||
# don't use a timeout.
|
||||
extraArgs, timeout=None)
|
||||
extraArgs, timeout=1800)
|
||||
sys.exit(status)
|
||||
|
|
|
@ -21,7 +21,7 @@ interface nsIContentSecurityPolicy;
|
|||
[ptr] native JSPrincipals(JSPrincipals);
|
||||
[ptr] native PrincipalArray(nsTArray<nsCOMPtr<nsIPrincipal> >);
|
||||
|
||||
[scriptable, uuid(825ffce8-962d-11e1-aef3-8f2b6188709b)]
|
||||
[scriptable, uuid(115d1081-373e-4837-8d12-d0f4874f3467)]
|
||||
interface nsIPrincipal : nsISerializable
|
||||
{
|
||||
/**
|
||||
|
@ -273,6 +273,13 @@ interface nsIPrincipal : nsISerializable
|
|||
* Returns true iif the principal is inside a browser element.
|
||||
*/
|
||||
readonly attribute boolean isInBrowserElement;
|
||||
|
||||
/**
|
||||
* Returns true if this principal has an unknown appId. This shouldn't
|
||||
* generally be used. We only expose it due to not providing the correct
|
||||
* appId everywhere where we construct principals.
|
||||
*/
|
||||
readonly attribute boolean unknownAppId;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -131,6 +131,7 @@ public:
|
|||
NS_IMETHOD GetAppStatus(uint16_t* aAppStatus);
|
||||
NS_IMETHOD GetAppId(uint32_t* aAppStatus);
|
||||
NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement);
|
||||
NS_IMETHOD GetUnknownAppId(bool* aUnknownAppId);
|
||||
#ifdef DEBUG
|
||||
virtual void dumpImpl();
|
||||
#endif
|
||||
|
@ -227,6 +228,7 @@ public:
|
|||
NS_IMETHOD GetAppStatus(uint16_t* aAppStatus);
|
||||
NS_IMETHOD GetAppId(uint32_t* aAppStatus);
|
||||
NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement);
|
||||
NS_IMETHOD GetUnknownAppId(bool* aUnknownAppId);
|
||||
#ifdef DEBUG
|
||||
virtual void dumpImpl();
|
||||
#endif
|
||||
|
|
|
@ -360,6 +360,13 @@ nsNullPrincipal::GetIsInBrowserElement(bool* aIsInBrowserElement)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNullPrincipal::GetUnknownAppId(bool* aUnknownAppId)
|
||||
{
|
||||
*aUnknownAppId = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* nsISerializable implementation
|
||||
*/
|
||||
|
|
|
@ -1111,6 +1111,13 @@ nsPrincipal::GetIsInBrowserElement(bool* aIsInBrowserElement)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrincipal::GetUnknownAppId(bool* aUnknownAppId)
|
||||
{
|
||||
*aUnknownAppId = mAppId == nsIScriptSecurityManager::UNKNOWN_APP_ID;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrincipal::Read(nsIObjectInputStream* aStream)
|
||||
{
|
||||
|
@ -1535,6 +1542,13 @@ nsExpandedPrincipal::GetIsInBrowserElement(bool* aIsInBrowserElement)
|
|||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsExpandedPrincipal::GetUnknownAppId(bool* aUnknownAppId)
|
||||
{
|
||||
*aUnknownAppId = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsExpandedPrincipal::GetScriptLocation(nsACString& aStr)
|
||||
{
|
||||
|
|
|
@ -61,6 +61,10 @@
|
|||
#include "mozilla/StandardInteger.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
// This should be probably defined on some other place... but I couldn't find it
|
||||
#define WEBAPPS_PERM_NAME "webapps-manage"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
@ -1403,7 +1407,25 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
|
|||
nsCaseInsensitiveCStringComparator()))
|
||||
{
|
||||
// every scheme can access another URI from the same scheme,
|
||||
// as long as they don't represent null principals.
|
||||
// as long as they don't represent null principals...
|
||||
// Or they don't require an special permission to do so
|
||||
// See bug#773886
|
||||
|
||||
bool hasFlags;
|
||||
rv = NS_URIChainHasFlags(targetBaseURI,
|
||||
nsIProtocolHandler::URI_CROSS_ORIGIN_NEEDS_WEBAPPS_PERM,
|
||||
&hasFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (hasFlags) {
|
||||
// In this case, we allow opening only if the source and target URIS
|
||||
// are on the same domain, or the opening URI has the webapps
|
||||
// permision granted
|
||||
if (!SecurityCompareURIs(sourceBaseURI,targetBaseURI) &&
|
||||
!nsContentUtils::IsExactSitePermAllow(aPrincipal,WEBAPPS_PERM_NAME)){
|
||||
return NS_ERROR_DOM_BAD_URI;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -265,6 +265,13 @@ nsSystemPrincipal::GetIsInBrowserElement(bool* aIsInBrowserElement)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSystemPrincipal::GetUnknownAppId(bool* aUnknownAppId)
|
||||
{
|
||||
*aUnknownAppId = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
// Methods implementing nsISerializable //
|
||||
//////////////////////////////////////////
|
||||
|
|
|
@ -2298,7 +2298,6 @@ ia64*-hpux*)
|
|||
DSO_LDOPTS="$DSO_LDOPTS -MACHINE:X86"
|
||||
fi
|
||||
|
||||
MOZ_CHECK_HEADERS(mmintrin.h)
|
||||
AC_DEFINE(_X86_)
|
||||
;;
|
||||
x86_64-*)
|
||||
|
@ -2977,11 +2976,6 @@ dnl Quota support
|
|||
MOZ_CHECK_HEADERS(sys/quota.h sys/sysmacros.h)
|
||||
MOZ_CHECK_HEADERS(linux/quota.h)
|
||||
|
||||
dnl Try for MMX support
|
||||
dnl NB - later gcc versions require -mmmx for this header to be successfully
|
||||
dnl included (or another option which implies it, such as -march=pentium-mmx)
|
||||
MOZ_CHECK_HEADERS(mmintrin.h)
|
||||
|
||||
MOZ_CHECK_HEADERS(sys/types.h netinet/in.h byteswap.h)
|
||||
|
||||
dnl Check whether the compiler supports the new-style C++ standard
|
||||
|
|
|
@ -570,6 +570,22 @@ public:
|
|||
// system principal, and true for a null principal.
|
||||
static bool IsSitePermDeny(nsIPrincipal* aPrincipal, const char* aType);
|
||||
|
||||
// Get a permission-manager setting for the given principal and type.
|
||||
// If the pref doesn't exist or if it isn't ALLOW_ACTION, false is
|
||||
// returned, otherwise true is returned. Always returns true for the
|
||||
// system principal, and false for a null principal.
|
||||
// This version checks the permission for an exact host match on
|
||||
// the principal
|
||||
static bool IsExactSitePermAllow(nsIPrincipal* aPrincipal, const char* aType);
|
||||
|
||||
// Get a permission-manager setting for the given principal and type.
|
||||
// If the pref doesn't exist or if it isn't DENY_ACTION, false is
|
||||
// returned, otherwise true is returned. Always returns false for the
|
||||
// system principal, and true for a null principal.
|
||||
// This version checks the permission for an exact host match on
|
||||
// the principal
|
||||
static bool IsExactSitePermDeny(nsIPrincipal* aPrincipal, const char* aType);
|
||||
|
||||
// Returns true if aDoc1 and aDoc2 have equal NodePrincipal()s.
|
||||
static bool HaveEqualPrincipals(nsIDocument* aDoc1, nsIDocument* aDoc2);
|
||||
|
||||
|
|
|
@ -886,12 +886,8 @@ nsContentSink::SelectDocAppCache(nsIApplicationCache *aLoadApplicationCache,
|
|||
"mDocument must implement nsIApplicationCacheContainer.");
|
||||
|
||||
if (aLoadApplicationCache) {
|
||||
nsAutoCString groupID;
|
||||
rv = aLoadApplicationCache->GetGroupID(groupID);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIURI> groupURI;
|
||||
rv = NS_NewURI(getter_AddRefs(groupURI), groupID);
|
||||
rv = aLoadApplicationCache->GetManifestURI(getter_AddRefs(groupURI));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool equal = false;
|
||||
|
@ -975,11 +971,7 @@ nsContentSink::SelectDocAppCacheNoManifest(nsIApplicationCache *aLoadApplication
|
|||
|
||||
// Return the uri and invoke the update process for the selected
|
||||
// application cache.
|
||||
nsAutoCString groupID;
|
||||
rv = aLoadApplicationCache->GetGroupID(groupID);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = NS_NewURI(aManifestURI, groupID);
|
||||
rv = aLoadApplicationCache->GetManifestURI(aManifestURI);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
*aAction = CACHE_SELECTION_UPDATE;
|
||||
|
|
|
@ -2877,7 +2877,7 @@ nsContentUtils::IsDraggableLink(const nsIContent* aContent) {
|
|||
}
|
||||
|
||||
static bool
|
||||
TestSitePerm(nsIPrincipal* aPrincipal, const char* aType, uint32_t aPerm)
|
||||
TestSitePerm(nsIPrincipal* aPrincipal, const char* aType, uint32_t aPerm, bool aExactHostMatch)
|
||||
{
|
||||
if (!aPrincipal) {
|
||||
// We always deny (i.e. don't allow) the permission if we don't have a
|
||||
|
@ -2890,7 +2890,12 @@ TestSitePerm(nsIPrincipal* aPrincipal, const char* aType, uint32_t aPerm)
|
|||
NS_ENSURE_TRUE(permMgr, false);
|
||||
|
||||
uint32_t perm;
|
||||
nsresult rv = permMgr->TestPermissionFromPrincipal(aPrincipal, aType, &perm);
|
||||
nsresult rv;
|
||||
if (aExactHostMatch) {
|
||||
rv = permMgr->TestExactPermissionFromPrincipal(aPrincipal, aType, &perm);
|
||||
} else {
|
||||
rv = permMgr->TestPermissionFromPrincipal(aPrincipal, aType, &perm);
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
return perm == aPerm;
|
||||
|
@ -2899,13 +2904,25 @@ TestSitePerm(nsIPrincipal* aPrincipal, const char* aType, uint32_t aPerm)
|
|||
bool
|
||||
nsContentUtils::IsSitePermAllow(nsIPrincipal* aPrincipal, const char* aType)
|
||||
{
|
||||
return TestSitePerm(aPrincipal, aType, nsIPermissionManager::ALLOW_ACTION);
|
||||
return TestSitePerm(aPrincipal, aType, nsIPermissionManager::ALLOW_ACTION, false);
|
||||
}
|
||||
|
||||
bool
|
||||
nsContentUtils::IsSitePermDeny(nsIPrincipal* aPrincipal, const char* aType)
|
||||
{
|
||||
return TestSitePerm(aPrincipal, aType, nsIPermissionManager::DENY_ACTION);
|
||||
return TestSitePerm(aPrincipal, aType, nsIPermissionManager::DENY_ACTION, false);
|
||||
}
|
||||
|
||||
bool
|
||||
nsContentUtils::IsExactSitePermAllow(nsIPrincipal* aPrincipal, const char* aType)
|
||||
{
|
||||
return TestSitePerm(aPrincipal, aType, nsIPermissionManager::ALLOW_ACTION, true);
|
||||
}
|
||||
|
||||
bool
|
||||
nsContentUtils::IsExactSitePermDeny(nsIPrincipal* aPrincipal, const char* aType)
|
||||
{
|
||||
return TestSitePerm(aPrincipal, aType, nsIPermissionManager::DENY_ACTION, true);
|
||||
}
|
||||
|
||||
static const char *gEventNames[] = {"event"};
|
||||
|
|
|
@ -2394,9 +2394,6 @@ nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
|
|||
mMayStartLayout = false;
|
||||
|
||||
mHaveInputEncoding = true;
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
nsresult rv = InitCSP(aChannel, getter_AddRefs(csp));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aReset) {
|
||||
Reset(aChannel, aLoadGroup);
|
||||
|
@ -2426,30 +2423,27 @@ nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
if (csp) {
|
||||
// Copy into principal
|
||||
nsIPrincipal* principal = GetPrincipal();
|
||||
principal->SetCsp(csp);
|
||||
#ifdef PR_LOGGING
|
||||
PR_LOG(gCspPRLog, PR_LOG_DEBUG,
|
||||
("Inserted CSP into principal %p", principal));
|
||||
#endif
|
||||
}
|
||||
nsresult rv = InitCSP(aChannel);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDocument::InitCSP(nsIChannel* aChannel, nsIContentSecurityPolicy **aCSP)
|
||||
nsDocument::InitCSP(nsIChannel* aChannel)
|
||||
{
|
||||
*aCSP = nullptr;
|
||||
if (CSPService::sCSPEnabled) {
|
||||
nsAutoCString tCspHeaderValue, tCspROHeaderValue;
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
|
||||
if (!httpChannel) {
|
||||
// no CSP for non http channels
|
||||
return NS_OK;
|
||||
}
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
if (!CSPService::sCSPEnabled) {
|
||||
#ifdef PR_LOGGING
|
||||
PR_LOG(gCspPRLog, PR_LOG_DEBUG,
|
||||
("CSP is disabled, skipping CSP init for document %p", this));
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoCString tCspHeaderValue, tCspROHeaderValue;
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
|
||||
if (httpChannel) {
|
||||
httpChannel->GetResponseHeader(
|
||||
NS_LITERAL_CSTRING("x-content-security-policy"),
|
||||
tCspHeaderValue);
|
||||
|
@ -2457,45 +2451,115 @@ nsDocument::InitCSP(nsIChannel* aChannel, nsIContentSecurityPolicy **aCSP)
|
|||
httpChannel->GetResponseHeader(
|
||||
NS_LITERAL_CSTRING("x-content-security-policy-report-only"),
|
||||
tCspROHeaderValue);
|
||||
NS_ConvertASCIItoUTF16 cspHeaderValue(tCspHeaderValue);
|
||||
NS_ConvertASCIItoUTF16 cspROHeaderValue(tCspROHeaderValue);
|
||||
|
||||
if (cspHeaderValue.IsEmpty() && cspROHeaderValue.IsEmpty()) {
|
||||
// no CSP header present, stop processing
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
NS_ConvertASCIItoUTF16 cspHeaderValue(tCspHeaderValue);
|
||||
NS_ConvertASCIItoUTF16 cspROHeaderValue(tCspROHeaderValue);
|
||||
|
||||
// ----- Figure out if we need to apply an app default CSP
|
||||
bool applyAppDefaultCSP = false;
|
||||
nsIPrincipal* principal = NodePrincipal();
|
||||
PRUint16 appStatus = nsIPrincipal::APP_STATUS_NOT_INSTALLED;
|
||||
bool unknownAppId;
|
||||
if (NS_SUCCEEDED(principal->GetUnknownAppId(&unknownAppId)) &&
|
||||
!unknownAppId &&
|
||||
NS_SUCCEEDED(principal->GetAppStatus(&appStatus))) {
|
||||
applyAppDefaultCSP = ( appStatus == nsIPrincipal::APP_STATUS_PRIVILEGED ||
|
||||
appStatus == nsIPrincipal::APP_STATUS_CERTIFIED);
|
||||
}
|
||||
#ifdef PR_LOGGING
|
||||
PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("CSP header specified for document %p", this));
|
||||
else
|
||||
PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("Failed to get app status from principal"));
|
||||
#endif
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
csp = do_CreateInstance("@mozilla.org/contentsecuritypolicy;1", &rv);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
// If there's no CSP to apply go ahead and return early
|
||||
if (!applyAppDefaultCSP &&
|
||||
cspHeaderValue.IsEmpty() &&
|
||||
cspROHeaderValue.IsEmpty()) {
|
||||
#ifdef PR_LOGGING
|
||||
PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("Failed to create CSP object: %x", rv));
|
||||
#endif
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Store the request context for violation reports
|
||||
csp->ScanRequestData(httpChannel);
|
||||
|
||||
// Start parsing the policy
|
||||
nsCOMPtr<nsIURI> chanURI;
|
||||
aChannel->GetURI(getter_AddRefs(chanURI));
|
||||
nsAutoCString aspec;
|
||||
chanURI->GetAsciiSpec(aspec);
|
||||
PR_LOG(gCspPRLog, PR_LOG_DEBUG,
|
||||
("no CSP for document, %s, %s",
|
||||
aspec.get(),
|
||||
applyAppDefaultCSP ? "is app" : "not an app"));
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("CSP Loaded"));
|
||||
PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("Document is an app or CSP header specified %p", this));
|
||||
#endif
|
||||
|
||||
// ReportOnly mode is enabled *only* if there are no regular-strength CSP
|
||||
// headers present. If there are, then we ignore the ReportOnly mode and
|
||||
// toss a warning into the error console, proceeding with enforcing the
|
||||
// regular-strength CSP.
|
||||
if (cspHeaderValue.IsEmpty()) {
|
||||
nsresult rv;
|
||||
csp = do_CreateInstance("@mozilla.org/contentsecuritypolicy;1", &rv);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
#ifdef PR_LOGGING
|
||||
PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("Failed to create CSP object: %x", rv));
|
||||
#endif
|
||||
return rv;
|
||||
}
|
||||
|
||||
// used as a "self" identifier for the CSP.
|
||||
nsCOMPtr<nsIURI> chanURI;
|
||||
aChannel->GetURI(getter_AddRefs(chanURI));
|
||||
|
||||
// Store the request context for violation reports
|
||||
csp->ScanRequestData(httpChannel);
|
||||
|
||||
// ----- process the app default policy, if necessary
|
||||
if (applyAppDefaultCSP) {
|
||||
nsAdoptingString appCSP;
|
||||
if (appStatus == nsIPrincipal::APP_STATUS_PRIVILEGED) {
|
||||
appCSP = Preferences::GetString("security.apps.privileged.CSP.default");
|
||||
NS_ASSERTION(appCSP, "App, but no default CSP in security.apps.privileged.CSP.default");
|
||||
} else if (appStatus == nsIPrincipal::APP_STATUS_CERTIFIED) {
|
||||
appCSP = Preferences::GetString("security.apps.certified.CSP.default");
|
||||
NS_ASSERTION(appCSP, "App, but no default CSP in security.apps.certified.CSP.default");
|
||||
}
|
||||
|
||||
if (appCSP)
|
||||
csp->RefinePolicy(appCSP, chanURI);
|
||||
}
|
||||
|
||||
// ----- if there's a full-strength CSP header, apply it.
|
||||
if (!cspHeaderValue.IsEmpty()) {
|
||||
// Need to tokenize the header value since multiple headers could be
|
||||
// concatenated into one comma-separated list of policies.
|
||||
// See RFC2616 section 4.2 (last paragraph)
|
||||
nsCharSeparatedTokenizer tokenizer(cspHeaderValue, ',');
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
const nsSubstring& policy = tokenizer.nextToken();
|
||||
csp->RefinePolicy(policy, chanURI);
|
||||
#ifdef PR_LOGGING
|
||||
{
|
||||
PR_LOG(gCspPRLog, PR_LOG_DEBUG,
|
||||
("CSP refined with policy: \"%s\"",
|
||||
NS_ConvertUTF16toUTF8(policy).get()));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// ----- if there's a report-only CSP header, apply it
|
||||
if (!cspROHeaderValue.IsEmpty()) {
|
||||
// post a warning and skip report-only CSP when both read only and regular
|
||||
// CSP policies are present since CSP only allows one policy and it can't
|
||||
// be partially report-only.
|
||||
if (applyAppDefaultCSP || !cspHeaderValue.IsEmpty()) {
|
||||
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
|
||||
"CSP", this,
|
||||
nsContentUtils::eDOM_PROPERTIES,
|
||||
"ReportOnlyCSPIgnored");
|
||||
#ifdef PR_LOGGING
|
||||
PR_LOG(gCspPRLog, PR_LOG_DEBUG,
|
||||
("Skipped report-only CSP init for document %p because another, enforced policy is set", this));
|
||||
#endif
|
||||
} else {
|
||||
// we can apply the report-only policy because there's no other CSP
|
||||
// applied.
|
||||
csp->SetReportOnlyMode(true);
|
||||
|
||||
// Need to tokenize the header value since multiple headers could be
|
||||
|
@ -2508,58 +2572,43 @@ nsDocument::InitCSP(nsIChannel* aChannel, nsIContentSecurityPolicy **aCSP)
|
|||
#ifdef PR_LOGGING
|
||||
{
|
||||
PR_LOG(gCspPRLog, PR_LOG_DEBUG,
|
||||
("CSP (report only) refined with policy: \"%s\"",
|
||||
("CSP (report-only) refined with policy: \"%s\"",
|
||||
NS_ConvertUTF16toUTF8(policy).get()));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
//XXX(sstamm): maybe we should post a warning when both read only and regular
|
||||
// CSP headers are present.
|
||||
|
||||
// Need to tokenize the header value since multiple headers could be
|
||||
// concatenated into one comma-separated list of policies.
|
||||
// See RFC2616 section 4.2 (last paragraph)
|
||||
nsCharSeparatedTokenizer tokenizer(cspHeaderValue, ',');
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
const nsSubstring& policy = tokenizer.nextToken();
|
||||
csp->RefinePolicy(policy, chanURI);
|
||||
#ifdef PR_LOGGING
|
||||
{
|
||||
PR_LOG(gCspPRLog, PR_LOG_DEBUG,
|
||||
("CSP refined with policy: \"%s\"",
|
||||
NS_ConvertUTF16toUTF8(policy).get()));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Check for frame-ancestor violation
|
||||
nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocumentContainer);
|
||||
if (docShell) {
|
||||
bool safeAncestry = false;
|
||||
|
||||
// PermitsAncestry sends violation reports when necessary
|
||||
rv = csp->PermitsAncestry(docShell, &safeAncestry);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!safeAncestry) {
|
||||
#ifdef PR_LOGGING
|
||||
PR_LOG(gCspPRLog, PR_LOG_DEBUG,
|
||||
("CSP doesn't like frame's ancestry, not loading."));
|
||||
#endif
|
||||
// stop! ERROR page!
|
||||
aChannel->Cancel(NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION);
|
||||
}
|
||||
}
|
||||
csp.forget(aCSP);
|
||||
}
|
||||
|
||||
// ----- Enforce frame-ancestor policy on any applied policies
|
||||
nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocumentContainer);
|
||||
if (docShell) {
|
||||
bool safeAncestry = false;
|
||||
|
||||
// PermitsAncestry sends violation reports when necessary
|
||||
rv = csp->PermitsAncestry(docShell, &safeAncestry);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!safeAncestry) {
|
||||
#ifdef PR_LOGGING
|
||||
PR_LOG(gCspPRLog, PR_LOG_DEBUG,
|
||||
("CSP doesn't like frame's ancestry, not loading."));
|
||||
#endif
|
||||
// stop! ERROR page!
|
||||
aChannel->Cancel(NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION);
|
||||
}
|
||||
}
|
||||
|
||||
if (csp) {
|
||||
// Copy into principal
|
||||
nsIPrincipal* principal = GetPrincipal();
|
||||
principal->SetCsp(csp);
|
||||
#ifdef PR_LOGGING
|
||||
else { //CSP was not enabled!
|
||||
PR_LOG(gCspPRLog, PR_LOG_DEBUG,
|
||||
("CSP is disabled, skipping CSP init for document %p", this));
|
||||
}
|
||||
("Inserted CSP into principal %p", principal));
|
||||
#endif
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -1274,7 +1274,7 @@ private:
|
|||
void DoUnblockOnload();
|
||||
|
||||
nsresult CheckFrameOptions();
|
||||
nsresult InitCSP(nsIChannel* aChannel, nsIContentSecurityPolicy **aCSP);
|
||||
nsresult InitCSP(nsIChannel* aChannel);
|
||||
|
||||
// Sets aElement to be the pending pointer lock element. Once this document's
|
||||
// node principal's URI is granted the "fullscreen" permission, the pointer
|
||||
|
|
|
@ -658,6 +658,7 @@ GK_ATOM(oncontextmenu, "oncontextmenu")
|
|||
GK_ATOM(oncopy, "oncopy")
|
||||
GK_ATOM(oncut, "oncut")
|
||||
GK_ATOM(ondatachange, "ondatachange")
|
||||
GK_ATOM(ondataerror, "ondataerror")
|
||||
GK_ATOM(ondblclick, "ondblclick")
|
||||
GK_ATOM(ondelivered, "ondelivered")
|
||||
GK_ATOM(ondevicecreated, "ondevicecreated")
|
||||
|
|
|
@ -195,6 +195,15 @@ nsMixedContentBlocker::ShouldProcess(PRUint32 aContentType,
|
|||
nsIPrincipal* aRequestPrincipal,
|
||||
PRInt16* aDecision)
|
||||
{
|
||||
if(!aContentLocation) {
|
||||
// aContentLocation may be null when a plugin is loading without an associated URI resource
|
||||
if(aContentType == TYPE_OBJECT) {
|
||||
return NS_OK;
|
||||
} else {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return ShouldLoad(aContentType, aContentLocation, aRequestingLocation,
|
||||
aRequestingContext, aMimeGuess, aExtra, aRequestPrincipal,
|
||||
aDecision);
|
||||
|
|
|
@ -367,6 +367,8 @@ MOCHITEST_FILES_B = \
|
|||
file_CSP_evalscript_main.html \
|
||||
file_CSP_evalscript_main.html^headers^ \
|
||||
file_CSP_evalscript_main.js \
|
||||
file_csp_bug768029.html \
|
||||
file_csp_bug768029.sjs \
|
||||
test_bug540854.html \
|
||||
bug540854.sjs \
|
||||
test_bug548463.html \
|
||||
|
|
|
@ -46,6 +46,7 @@ MOCHITEST_CHROME_FILES = \
|
|||
test_bug682305.html \
|
||||
test_bug780199.xul \
|
||||
test_bug780529.xul \
|
||||
test_csp_bug768029.html \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -0,0 +1,221 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=768029
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for CSP on trusted/certified apps -- bug 768029</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=768029">Mozilla Bug 768029</a>
|
||||
<p id="display"></p>
|
||||
<div id="content">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
/** Test for Bug 768029 **/
|
||||
|
||||
// Note: we don't have to inspect all the different operations of CSP,
|
||||
// we're just looking for specific differences in behavior that indicate
|
||||
// a default CSP got applied.
|
||||
const DEFAULT_CSP_PRIV = "default-src *; script-src 'self'; style-src 'self' 'unsafe-inline'; object-src 'none'";
|
||||
const DEFAULT_CSP_CERT = "default-src *; script-src 'self'; style-src 'self'; object-src 'none'";
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var gData = [
|
||||
{
|
||||
app: "https://example.com/manifest.webapp",
|
||||
appStatus: Components.interfaces.nsIPrincipal.APP_STATUS_INSTALLED,
|
||||
origin: "https://example.com",
|
||||
uri: "https://example.com/tests/content/base/test/file_csp_bug768029.html",
|
||||
statusString: "installed app",
|
||||
expectedTestResults: {
|
||||
max_tests: 7, /* number of bools below plus one for the status check */
|
||||
cross_origin: { img: true, script: true, style: true },
|
||||
same_origin: { img: true, script: true, style: true },
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
app: "https://example.com/manifest_priv.webapp",
|
||||
appStatus: Components.interfaces.nsIPrincipal.APP_STATUS_PRIVILEGED,
|
||||
origin: "https://example.com",
|
||||
uri: "https://example.com/tests/content/base/test/file_csp_bug768029.html",
|
||||
statusString: "privileged app",
|
||||
expectedTestResults: {
|
||||
max_tests: 7, /* number of bools below plus one for the status check */
|
||||
cross_origin: { img: true, script: false, style: false },
|
||||
same_origin: { img: true, script: true, style: true },
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
app: "https://example.com/manifest_cert.webapp",
|
||||
appStatus: Components.interfaces.nsIPrincipal.APP_STATUS_CERTIFIED,
|
||||
origin: "https://example.com",
|
||||
uri: "https://example.com/tests/content/base/test/file_csp_bug768029.html",
|
||||
statusString: "certified app",
|
||||
expectedTestResults: {
|
||||
max_tests: 7, /* number of bools below plus one for the status check */
|
||||
cross_origin: { img: true, script: false, style: false },
|
||||
same_origin: { img: true, script: true, style: true },
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
// Observer for watching allowed loads and blocked attempts
|
||||
function ThingyListener(app, iframe) {
|
||||
Services.obs.addObserver(this, "csp-on-violate-policy", false);
|
||||
Services.obs.addObserver(this, "http-on-modify-request", false);
|
||||
dump("added observers\n");
|
||||
// keep track of which app ID this test is monitoring.
|
||||
this._testData = app;
|
||||
this._expectedResults = app.expectedTestResults;
|
||||
this._resultsRecorded = { cross_origin: {}, same_origin: {}};
|
||||
this._iframe = iframe;
|
||||
this._countedTests = 0;
|
||||
}
|
||||
ThingyListener.prototype = {
|
||||
|
||||
observe: function(subject, topic, data) {
|
||||
// make sure to only observe app-generated calls to the helper for this test.
|
||||
var testpat = new RegExp("file_csp_bug768029\\.sjs");
|
||||
|
||||
// used to extract which kind of load this is (img, script, etc).
|
||||
var typepat = new RegExp("type=([\\_a-z0-9]+)");
|
||||
|
||||
// used to identify whether it's cross-origin or same-origin loads
|
||||
// (the applied CSP allows same-origin loads).
|
||||
var originpat = new RegExp("origin=([\\_a-z0-9]+)");
|
||||
|
||||
if (topic === "http-on-modify-request") {
|
||||
// Matching requests on this topic were allowed by the csp
|
||||
var chan = subject.QueryInterface(Components.interfaces.nsIHttpChannel);
|
||||
var uri = chan.URI;
|
||||
// ignore irrelevent URIs
|
||||
if (!testpat.test(uri.asciiSpec)) return;
|
||||
|
||||
var loadType = typepat.exec(uri.asciiSpec)[1];
|
||||
var originType = originpat.exec(uri.asciiSpec)[1];
|
||||
|
||||
// skip duplicate hits to this topic (potentially document loads
|
||||
// may generate duplicate loads.
|
||||
if (this._resultsRecorded[originType] &&
|
||||
this._resultsRecorded[originType][loadType]) {
|
||||
return;
|
||||
}
|
||||
var message = originType + " : " + loadType + " should be " +
|
||||
(this._expectedResults[originType][loadType] ? "allowed" : "blocked");
|
||||
ok(this._expectedResults[originType][loadType] == true, message);
|
||||
this._resultsRecorded[originType][loadType] = true;
|
||||
this._countedTests++;
|
||||
}
|
||||
else if (topic === "csp-on-violate-policy") {
|
||||
// Matching hits on this topic were blocked by the csp
|
||||
var uri = subject.QueryInterface(Components.interfaces.nsIURI);
|
||||
// ignore irrelevent URIs
|
||||
if (!testpat.test(uri.asciiSpec)) return;
|
||||
|
||||
var loadType = typepat.exec(uri.asciiSpec)[1];
|
||||
var originType = originpat.exec(uri.asciiSpec)[1];
|
||||
|
||||
// skip duplicate hits to this topic (potentially document loads
|
||||
// may generate duplicate loads.
|
||||
if (this._resultsRecorded[originType] &&
|
||||
this._resultsRecorded[originType][loadType]) {
|
||||
return;
|
||||
}
|
||||
|
||||
var message = originType + " : " + loadType + " should be " +
|
||||
(this._expectedResults[originType][loadType] ? "allowed" : "blocked");
|
||||
ok(this._expectedResults[originType][loadType] == false, message);
|
||||
this._resultsRecorded[originType][loadType] = true;
|
||||
this._countedTests++;
|
||||
}
|
||||
else {
|
||||
// wrong topic! Nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
this._checkForFinish();
|
||||
},
|
||||
|
||||
_checkForFinish: function() {
|
||||
// check to see if there are load tests still pending.
|
||||
// (All requests triggered by the app should hit one of the
|
||||
// two observer topics.)
|
||||
if (this._countedTests == this._expectedResults.max_tests) {
|
||||
Services.obs.removeObserver(this, "csp-on-violate-policy");
|
||||
Services.obs.removeObserver(this, "http-on-modify-request");
|
||||
dump("removed observers\n");
|
||||
checkedCount++;
|
||||
if (checkedCount == checksTodo) {
|
||||
SpecialPowers.removePermission("browser", "https://example.com");
|
||||
SimpleTest.finish();
|
||||
} else {
|
||||
gTestRunner.next();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// verify the status of the app
|
||||
checkAppStatus: function() {
|
||||
var principal = this._iframe.contentDocument.nodePrincipal;
|
||||
if (this._testData.app) {
|
||||
is(principal.appStatus, this._testData.appStatus,
|
||||
"iframe principal's app status doesn't match the expected app status.");
|
||||
this._countedTests++;
|
||||
this._checkForFinish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var content = document.getElementById('content');
|
||||
var checkedCount = 0; // number of apps checked
|
||||
var checksTodo = gData.length;
|
||||
|
||||
// quick check to make sure we can test apps:
|
||||
is('appStatus' in document.nodePrincipal, true,
|
||||
'appStatus should be present in nsIPrincipal, if not the rest of this test will fail');
|
||||
|
||||
function runTest() {
|
||||
for (var i = 0; i < gData.length; i++) {
|
||||
let data = gData[i];
|
||||
var iframe = document.createElement('iframe');
|
||||
|
||||
// watch for successes and failures
|
||||
var examiner = new ThingyListener(data, iframe);
|
||||
|
||||
iframe.setAttribute('mozapp', data.app);
|
||||
iframe.setAttribute('mozbrowser', 'true');
|
||||
iframe.addEventListener('load', examiner.checkAppStatus.bind(examiner));
|
||||
iframe.src = data.uri;
|
||||
|
||||
content.appendChild(iframe);
|
||||
|
||||
yield;
|
||||
}
|
||||
}
|
||||
|
||||
var gTestRunner = runTest();
|
||||
|
||||
// load the default CSP and pref it on
|
||||
SpecialPowers.addPermission("browser", true, "https://example.com");
|
||||
SpecialPowers.pushPrefEnv({'set': [["dom.mozBrowserFramesEnabled", true],
|
||||
["security.apps.privileged.CSP.default", DEFAULT_CSP_PRIV],
|
||||
["security.apps.certified.CSP.default", DEFAULT_CSP_CERT]]},
|
||||
function() { gTestRunner.next(); });
|
||||
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,25 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=768029
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>This is an app for testing</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="file_csp_bug768029.sjs?type=style&origin=same_origin" />
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="http://example.com/tests/content/base/test/file_csp_bug768029.sjs?type=style&origin=cross_origin" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script src="file_csp_bug768029.sjs?type=script&origin=same_origin"></script>
|
||||
<script src="http://example.com/tests/content/base/test/file_csp_bug768029.sjs?type=script&origin=cross_origin"></script>
|
||||
<img src="file_csp_bug768029.sjs?type=img&origin=same_origin" />
|
||||
<img src="http://example.com/tests/content/base/test/file_csp_bug768029.sjs?type=img&origin=cross_origin" />
|
||||
|
||||
Test for CSP applied to (simulated) app.
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,29 @@
|
|||
function handleRequest(request, response) {
|
||||
|
||||
var query = {};
|
||||
|
||||
request.queryString.split('&').forEach(function(val) {
|
||||
var [name, value] = val.split('=');
|
||||
query[name] = unescape(value);
|
||||
});
|
||||
response.setHeader("Cache-Control", "no-cache", false);
|
||||
|
||||
if ("type" in query) {
|
||||
switch (query.type) {
|
||||
case "script":
|
||||
response.setHeader("Content-Type", "application/javascript");
|
||||
response.write("\n\ndocument.write('<pre>script loaded\\n</pre>');\n\n");
|
||||
return;
|
||||
case "style":
|
||||
response.setHeader("Content-Type", "text/css");
|
||||
response.write("\n\n.cspfoo { color:red; }\n\n");
|
||||
return;
|
||||
case "img":
|
||||
response.setHeader("Content-Type", "image/png");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
response.setHeader("Content-Type", "text/plain");
|
||||
response.write("ohnoes!");
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#include "AudioBuffer.h"
|
||||
#include "mozilla/dom/AudioBufferBinding.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "AudioContext.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(AudioBuffer)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AudioBuffer)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContext)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mChannels)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
NS_DROP_JS_OBJECTS(tmp, AudioBuffer);
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AudioBuffer)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContext)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(AudioBuffer)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
|
||||
for (uint32_t i = 0; i < tmp->mChannels.Length(); ++i) {
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mChannels[i])
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(AudioBuffer)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(AudioBuffer)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AudioBuffer)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
AudioBuffer::AudioBuffer(AudioContext* aContext, uint32_t aLength,
|
||||
uint32_t aSampleRate)
|
||||
: mContext(aContext),
|
||||
mLength(aLength),
|
||||
mSampleRate(aSampleRate)
|
||||
{
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
|
||||
AudioBuffer::~AudioBuffer()
|
||||
{
|
||||
// Drop the JS object reference if we're still holding to the channels
|
||||
if (mChannels.Length()) {
|
||||
NS_DROP_JS_OBJECTS(this, AudioBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
AudioBuffer::InitializeBuffers(uint32_t aNumberOfChannels, JSContext* aJSContext)
|
||||
{
|
||||
if (!mChannels.SetCapacity(aNumberOfChannels)) {
|
||||
return false;
|
||||
}
|
||||
for (uint32_t i = 0; i < aNumberOfChannels; ++i) {
|
||||
JSObject* array = JS_NewFloat32Array(aJSContext, mLength);
|
||||
if (!array) {
|
||||
return false;
|
||||
}
|
||||
mChannels.AppendElement(array);
|
||||
}
|
||||
|
||||
NS_HOLD_JS_OBJECTS(this, AudioBuffer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
AudioBuffer::WrapObject(JSContext* aCx, JSObject* aScope,
|
||||
bool* aTriedToWrap)
|
||||
{
|
||||
return AudioBufferBinding::Wrap(aCx, aScope, this, aTriedToWrap);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
AudioBuffer::GetChannelData(JSContext* aJSContext, uint32_t aChannel,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
if (aChannel >= mChannels.Length()) {
|
||||
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
return mChannels[aChannel];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "EnableWebAudioCheck.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsTArray.h"
|
||||
#include "AudioContext.h"
|
||||
|
||||
struct JSContext;
|
||||
struct JSObject;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ErrorResult;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class AudioBuffer MOZ_FINAL : public nsISupports,
|
||||
public nsWrapperCache,
|
||||
public EnableWebAudioCheck
|
||||
{
|
||||
public:
|
||||
AudioBuffer(AudioContext* aContext, uint32_t aLength,
|
||||
uint32_t aSampleRate);
|
||||
~AudioBuffer();
|
||||
|
||||
// This function needs to be called in order to allocate
|
||||
// all of the channels. It is fallible!
|
||||
bool InitializeBuffers(uint32_t aNumberOfChannels,
|
||||
JSContext* aJSContext);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(AudioBuffer)
|
||||
|
||||
AudioContext* GetParentObject() const
|
||||
{
|
||||
return mContext;
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope,
|
||||
bool* aTriedToWrap);
|
||||
|
||||
float SampleRate() const
|
||||
{
|
||||
return mSampleRate;
|
||||
}
|
||||
|
||||
uint32_t Length() const
|
||||
{
|
||||
return mLength;
|
||||
}
|
||||
|
||||
float Duration() const
|
||||
{
|
||||
return mLength / mSampleRate;
|
||||
}
|
||||
|
||||
uint32_t NumberOfChannels() const
|
||||
{
|
||||
return mChannels.Length();
|
||||
}
|
||||
|
||||
JSObject* GetChannelData(JSContext* aJSContext, uint32_t aChannel,
|
||||
ErrorResult& aRv) const;
|
||||
|
||||
private:
|
||||
nsRefPtr<AudioContext> mContext;
|
||||
FallibleTArray<JSObject*> mChannels;
|
||||
uint32_t mLength;
|
||||
float mSampleRate;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@
|
|||
#include "mozilla/dom/AudioContextBinding.h"
|
||||
#include "AudioDestinationNode.h"
|
||||
#include "AudioBufferSourceNode.h"
|
||||
#include "AudioBuffer.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -63,6 +64,19 @@ AudioContext::CreateBufferSource()
|
|||
return bufferNode.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<AudioBuffer>
|
||||
AudioContext::CreateBuffer(JSContext* aJSContext, uint32_t aNumberOfChannels,
|
||||
uint32_t aLength, float aSampleRate,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsRefPtr<AudioBuffer> buffer = new AudioBuffer(this, aLength, aSampleRate);
|
||||
if (!buffer->InitializeBuffers(aNumberOfChannels, aJSContext)) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return nullptr;
|
||||
}
|
||||
return buffer.forget();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ namespace dom {
|
|||
|
||||
class AudioDestinationNode;
|
||||
class AudioBufferSourceNode;
|
||||
class AudioBuffer;
|
||||
|
||||
class AudioContext MOZ_FINAL : public nsISupports,
|
||||
public nsWrapperCache,
|
||||
|
@ -55,6 +56,11 @@ public:
|
|||
|
||||
already_AddRefed<AudioBufferSourceNode> CreateBufferSource();
|
||||
|
||||
already_AddRefed<AudioBuffer>
|
||||
CreateBuffer(JSContext* aJSContext, uint32_t aNumberOfChannels,
|
||||
uint32_t aLength, float aSampleRate,
|
||||
ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIDOMWindow> mWindow;
|
||||
nsRefPtr<AudioDestinationNode> mDestination;
|
||||
|
|
|
@ -15,6 +15,7 @@ LIBRARY_NAME := gkconwebaudio_s
|
|||
LIBXUL_LIBRARY := 1
|
||||
|
||||
CPPSRCS := \
|
||||
AudioBuffer.cpp \
|
||||
AudioBufferSourceNode.cpp \
|
||||
AudioContext.cpp \
|
||||
AudioDestinationNode.cpp \
|
||||
|
@ -25,6 +26,7 @@ CPPSRCS := \
|
|||
|
||||
EXPORTS_NAMESPACES := mozilla/dom
|
||||
EXPORTS_mozilla/dom := \
|
||||
AudioBuffer.h \
|
||||
AudioBufferSourceNode.h \
|
||||
AudioDestinationNode.h \
|
||||
AudioNode.h \
|
||||
|
|
|
@ -11,6 +11,7 @@ relativesrcdir := @relativesrcdir@
|
|||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MOCHITEST_FILES := \
|
||||
test_AudioBuffer.html \
|
||||
test_AudioContext.html \
|
||||
$(NULL)
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test whether we can create an AudioContext interface</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(function() {
|
||||
SpecialPowers.setBoolPref("media.webaudio.enabled", true);
|
||||
var ac = new mozAudioContext();
|
||||
var buffer = ac.createBuffer(2, 2048, 44100);
|
||||
SpecialPowers.gc(); // Make sure that our channels are accessible after GC
|
||||
ok(buffer, "Buffer was allocated successfully");
|
||||
is(buffer.sampleRate, 44100, "Correct sample rate");
|
||||
is(buffer.length, 2048, "Correct length");
|
||||
ok(Math.abs(buffer.duration - 2048 / 44100) < 0.0001, "Correct duration");
|
||||
is(buffer.numberOfChannels, 2, "Correct number of channels");
|
||||
for (var i = 0; i < buffer.numberOfChannels; ++i) {
|
||||
var buf = buffer.getChannelData(i);
|
||||
ok(buf, "Buffer index " + i + " exists");
|
||||
ok(buf instanceof Float32Array, "Result is a typed array");
|
||||
is(buf.length, buffer.length, "Correct length");
|
||||
var foundNonZero = false;
|
||||
for (var j = 0; j < buf.length; ++j) {
|
||||
if (buf[j] != 0) {
|
||||
foundNonZero = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ok(!foundNonZero, "Buffer " + i + " should be initialized to 0");
|
||||
}
|
||||
SpecialPowers.clearUserPref("media.webaudio.enabled");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -32,23 +32,22 @@
|
|||
SimpleTest.is(getDocShellType(typeContentFrame), Ci.nsIDocShellTreeItem.typeContent,
|
||||
"iframe with mozFrameType='content' in chrome document is typeContent");
|
||||
|
||||
// avoid closing the window from within the onload event handler to see
|
||||
// whether that fixes the intermittent orange in bug 772823
|
||||
SimpleTest.executeSoon(function () {
|
||||
// Wait for the window to be closed before finishing the test
|
||||
let ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
|
||||
.getService(Components.interfaces.nsIWindowWatcher);
|
||||
ww.registerNotification(function windowObs(subject, topic, data) {
|
||||
if (topic == "domwindowclosed") {
|
||||
ww.unregisterNotification(windowObs);
|
||||
// Wait for the window to be closed before finishing the test
|
||||
let ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
|
||||
.getService(Components.interfaces.nsIWindowWatcher);
|
||||
ww.registerNotification(function windowObs(subject, topic, data) {
|
||||
if (topic == "domwindowclosed") {
|
||||
ww.unregisterNotification(windowObs);
|
||||
|
||||
SimpleTest.executeSoon(function () {
|
||||
SimpleTest.waitForFocus(function() {
|
||||
SimpleTest.finish();
|
||||
}, opener);
|
||||
}
|
||||
});
|
||||
|
||||
window.close();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
window.close();
|
||||
}
|
||||
]]></script>
|
||||
</window>
|
||||
|
|
|
@ -505,6 +505,7 @@ using mozilla::dom::indexedDB::IDBWrapperCache;
|
|||
#include "nsIDOMMobileConnection.h"
|
||||
#endif
|
||||
#include "USSDReceivedEvent.h"
|
||||
#include "DataErrorEvent.h"
|
||||
#include "mozilla/dom/network/Utils.h"
|
||||
|
||||
#ifdef MOZ_B2G_RIL
|
||||
|
@ -1507,6 +1508,9 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
|||
NS_DEFINE_CLASSINFO_DATA(USSDReceivedEvent, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
|
||||
NS_DEFINE_CLASSINFO_DATA(DataErrorEvent, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
|
||||
NS_DEFINE_CLASSINFO_DATA(CSSFontFaceRule, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(CSSFontFaceStyleDecl, nsCSSStyleDeclSH,
|
||||
|
@ -4158,6 +4162,11 @@ nsDOMClassInfo::Init()
|
|||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEvent)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(DataErrorEvent, nsIDOMDataErrorEvent)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMDataErrorEvent)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEvent)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(CSSFontFaceRule, nsIDOMCSSFontFaceRule)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSFontFaceRule)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
|
|
@ -413,6 +413,8 @@ DOMCI_CLASS(MozMobileConnection)
|
|||
|
||||
DOMCI_CLASS(USSDReceivedEvent)
|
||||
|
||||
DOMCI_CLASS(DataErrorEvent)
|
||||
|
||||
// @font-face in CSS
|
||||
DOMCI_CLASS(CSSFontFaceRule)
|
||||
DOMCI_CLASS(CSSFontFaceStyleDecl)
|
||||
|
|
|
@ -66,8 +66,12 @@
|
|||
|
||||
DOMInterfaces = {
|
||||
|
||||
'AudioBuffer' : {
|
||||
},
|
||||
|
||||
'mozAudioContext': {
|
||||
'nativeType': 'AudioContext',
|
||||
'implicitJSContext': [ 'createBuffer' ],
|
||||
},
|
||||
|
||||
'AudioNode' : {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "Skeleton.h"
|
||||
#include "mozilla/dom/SkeletonBinding.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
|
|
@ -61,6 +61,17 @@ BluetoothDevice::BluetoothDevice(nsPIDOMWindow* aOwner,
|
|||
aValue.get_ArrayOfBluetoothNamedValue();
|
||||
for (uint32_t i = 0; i < values.Length(); ++i) {
|
||||
SetPropertyByValue(values[i]);
|
||||
if (values[i].name().EqualsLiteral("Path")) {
|
||||
// Since this is our signal handler string, set it as we set the property
|
||||
// in the object. Odd place to do it, but makes more sense than in
|
||||
// SetPropertyByValue.
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
if (!bs) {
|
||||
NS_WARNING("BluetoothService not available!");
|
||||
} else {
|
||||
bs->RegisterBluetoothSignalHandler(mPath, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,14 +111,8 @@ BluetoothDevice::SetPropertyByValue(const BluetoothNamedValue& aValue)
|
|||
if (name.EqualsLiteral("Name")) {
|
||||
mName = value.get_nsString();
|
||||
} else if (name.EqualsLiteral("Path")) {
|
||||
MOZ_ASSERT(value.get_nsString().Length() > 0);
|
||||
mPath = value.get_nsString();
|
||||
NS_WARNING(NS_ConvertUTF16toUTF8(mPath).get());
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
if (!bs) {
|
||||
NS_WARNING("BluetoothService not available!");
|
||||
} else {
|
||||
bs->RegisterBluetoothSignalHandler(mPath, this);
|
||||
}
|
||||
} else if (name.EqualsLiteral("Address")) {
|
||||
mAddress = value.get_nsString();
|
||||
} else if (name.EqualsLiteral("Class")) {
|
||||
|
|
|
@ -65,11 +65,11 @@ NS_IMETHODIMP
|
|||
BluetoothReplyRunnable::Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mDOMRequest);
|
||||
MOZ_ASSERT(mReply);
|
||||
|
||||
nsresult rv;
|
||||
|
||||
MOZ_ASSERT(mDOMRequest);
|
||||
|
||||
if (mReply->type() != BluetoothReply::TBluetoothReplySuccess) {
|
||||
rv = FireReply(JSVAL_VOID);
|
||||
} else {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "mozilla/Util.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
|
||||
#include "mozilla/ipc/UnixSocket.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIDOMDOMRequest.h"
|
||||
#include "nsIObserverService.h"
|
||||
|
@ -242,10 +243,9 @@ BluetoothService::Create()
|
|||
return new BluetoothGonkService();
|
||||
#elif defined(MOZ_BLUETOOTH_DBUS)
|
||||
return new BluetoothDBusService();
|
||||
#else
|
||||
#endif
|
||||
NS_WARNING("No platform support for bluetooth!");
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -269,8 +269,6 @@ BluetoothService::Init()
|
|||
return false;
|
||||
}
|
||||
|
||||
RegisterBluetoothSignalHandler(NS_LITERAL_STRING(LOCAL_AGENT_PATH), this);
|
||||
RegisterBluetoothSignalHandler(NS_LITERAL_STRING(REMOTE_AGENT_PATH), this);
|
||||
mRegisteredForLocalAgent = true;
|
||||
|
||||
return true;
|
||||
|
@ -360,16 +358,6 @@ BluetoothService::StartStopBluetooth(bool aStart)
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
#ifdef DEBUG
|
||||
if (aStart && mLastRequestedEnable) {
|
||||
MOZ_ASSERT(false, "Calling Start twice in a row!");
|
||||
}
|
||||
else if (!aStart && !mLastRequestedEnable) {
|
||||
MOZ_ASSERT(false, "Calling Stop twice in a row!");
|
||||
}
|
||||
mLastRequestedEnable = aStart;
|
||||
#endif
|
||||
|
||||
if (gInShutdown) {
|
||||
if (aStart) {
|
||||
// Don't try to start if we're already shutting down.
|
||||
|
@ -394,6 +382,16 @@ BluetoothService::StartStopBluetooth(bool aStart)
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
if (aStart) {
|
||||
RegisterBluetoothSignalHandler(NS_LITERAL_STRING(LOCAL_AGENT_PATH), this);
|
||||
RegisterBluetoothSignalHandler(NS_LITERAL_STRING(REMOTE_AGENT_PATH), this);
|
||||
|
||||
BluetoothManagerList::ForwardIterator iter(mLiveManagers);
|
||||
while (iter.HasMore()) {
|
||||
RegisterBluetoothSignalHandler(NS_LITERAL_STRING("/"), (BluetoothSignalObserver*)iter.GetNext());
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable = new ToggleBtTask(aStart);
|
||||
rv = mBluetoothCommandThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -697,7 +695,7 @@ SetJsObject(JSContext* aContext,
|
|||
JSObject* aObj,
|
||||
const InfallibleTArray<BluetoothNamedValue>& aData)
|
||||
{
|
||||
for (int i = 0; i < aData.Length(); i++) {
|
||||
for (uint32_t i = 0; i < aData.Length(); i++) {
|
||||
jsval v;
|
||||
if (aData[i].value().type() == BluetoothValue::TnsString) {
|
||||
nsString data = aData[i].value().get_nsString();
|
||||
|
|
|
@ -14,6 +14,12 @@
|
|||
#include "nsIThread.h"
|
||||
#include "nsTObserverArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
class UnixSocketConsumer;
|
||||
}
|
||||
}
|
||||
|
||||
BEGIN_BLUETOOTH_NAMESPACE
|
||||
|
||||
class BluetoothManager;
|
||||
|
@ -226,14 +232,12 @@ public:
|
|||
virtual nsresult
|
||||
GetSocketViaService(const nsAString& aObjectPath,
|
||||
const nsAString& aService,
|
||||
int aType,
|
||||
BluetoothSocketType aType,
|
||||
bool aAuth,
|
||||
bool aEncrypt,
|
||||
mozilla::ipc::UnixSocketConsumer* aSocketConsumer,
|
||||
BluetoothReplyRunnable* aRunnable) = 0;
|
||||
|
||||
virtual bool
|
||||
CloseSocket(int aFd, BluetoothReplyRunnable* aRunnable) = 0;
|
||||
|
||||
virtual bool
|
||||
SetPinCodeInternal(const nsAString& aDeviceAddress, const nsAString& aPinCode,
|
||||
BluetoothReplyRunnable* aRunnable) = 0;
|
||||
|
|
|
@ -0,0 +1,175 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/*
|
||||
* Copyright 2009, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* NOTE: Due to being based on the dbus compatibility layer for
|
||||
* android's bluetooth implementation, this file is licensed under the
|
||||
* apache license instead of MPL.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <bluetooth/bluetooth.h>
|
||||
#include <bluetooth/sco.h>
|
||||
#include <bluetooth/rfcomm.h>
|
||||
#include <bluetooth/l2cap.h>
|
||||
|
||||
#include "BluetoothUnixSocketConnector.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
USING_BLUETOOTH_NAMESPACE
|
||||
|
||||
static const int RFCOMM_SO_SNDBUF = 70 * 1024; // 70 KB send buffer
|
||||
|
||||
static
|
||||
int get_bdaddr(const char *str, bdaddr_t *ba)
|
||||
{
|
||||
char *d = ((char*)ba) + 5, *endp;
|
||||
for (int i = 0; i < 6; i++) {
|
||||
*d-- = strtol(str, &endp, 16);
|
||||
MOZ_ASSERT(!(*endp != ':' && i != 5));
|
||||
str = endp + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
BluetoothUnixSocketConnector::BluetoothUnixSocketConnector(
|
||||
BluetoothSocketType aType,
|
||||
int aChannel,
|
||||
bool aAuth,
|
||||
bool aEncrypt) : mType(aType)
|
||||
, mChannel(aChannel)
|
||||
, mAuth(aAuth)
|
||||
, mEncrypt(aEncrypt)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
BluetoothUnixSocketConnector::Create()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
int lm = 0;
|
||||
int fd = -1;
|
||||
int sndbuf;
|
||||
|
||||
switch (mType) {
|
||||
case BluetoothSocketType::RFCOMM:
|
||||
fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
|
||||
break;
|
||||
case BluetoothSocketType::SCO:
|
||||
fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
|
||||
break;
|
||||
case BluetoothSocketType::L2CAP:
|
||||
fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fd < 0) {
|
||||
NS_WARNING("Could not open bluetooth socket!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* kernel does not yet support LM for SCO */
|
||||
switch (mType) {
|
||||
case BluetoothSocketType::RFCOMM:
|
||||
lm |= mAuth ? RFCOMM_LM_AUTH : 0;
|
||||
lm |= mEncrypt ? RFCOMM_LM_ENCRYPT : 0;
|
||||
lm |= (mAuth && mEncrypt) ? RFCOMM_LM_SECURE : 0;
|
||||
break;
|
||||
case BluetoothSocketType::L2CAP:
|
||||
lm |= mAuth ? L2CAP_LM_AUTH : 0;
|
||||
lm |= mEncrypt ? L2CAP_LM_ENCRYPT : 0;
|
||||
lm |= (mAuth && mEncrypt) ? L2CAP_LM_SECURE : 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (lm) {
|
||||
if (setsockopt(fd, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm))) {
|
||||
NS_WARNING("setsockopt(RFCOMM_LM) failed, throwing");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (mType == BluetoothSocketType::RFCOMM) {
|
||||
sndbuf = RFCOMM_SO_SNDBUF;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf))) {
|
||||
NS_WARNING("setsockopt(SO_SNDBUF) failed, throwing");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothUnixSocketConnector::ConnectInternal(int aFd, const char* aAddress)
|
||||
{
|
||||
int n = 1;
|
||||
setsockopt(aFd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
|
||||
|
||||
socklen_t addr_sz;
|
||||
struct sockaddr *addr;
|
||||
bdaddr_t bd_address_obj;
|
||||
|
||||
if (get_bdaddr(aAddress, &bd_address_obj)) {
|
||||
NS_WARNING("Can't get bluetooth address!");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (mType) {
|
||||
case BluetoothSocketType::RFCOMM:
|
||||
struct sockaddr_rc addr_rc;
|
||||
addr = (struct sockaddr *)&addr_rc;
|
||||
addr_sz = sizeof(addr_rc);
|
||||
|
||||
memset(addr, 0, addr_sz);
|
||||
addr_rc.rc_family = AF_BLUETOOTH;
|
||||
addr_rc.rc_channel = mChannel;
|
||||
memcpy(&addr_rc.rc_bdaddr, &bd_address_obj, sizeof(bdaddr_t));
|
||||
break;
|
||||
case BluetoothSocketType::SCO:
|
||||
struct sockaddr_sco addr_sco;
|
||||
addr = (struct sockaddr *)&addr_sco;
|
||||
addr_sz = sizeof(addr_sco);
|
||||
|
||||
memset(addr, 0, addr_sz);
|
||||
addr_sco.sco_family = AF_BLUETOOTH;
|
||||
memcpy(&addr_sco.sco_bdaddr, &bd_address_obj, sizeof(bdaddr_t));
|
||||
break;
|
||||
default:
|
||||
NS_WARNING("Socket type unknown!");
|
||||
return false;
|
||||
}
|
||||
|
||||
int ret = connect(aFd, addr, addr_sz);
|
||||
|
||||
if (ret) {
|
||||
#if DEBUG
|
||||
//LOG("Socket connect errno=%d\n", errno);
|
||||
#endif
|
||||
NS_WARNING("Socket connect error!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 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 mozilla_dom_bluetooth_BluetoothUnixSocketConnector_h
|
||||
#define mozilla_dom_bluetooth_BluetoothUnixSocketConnector_h
|
||||
|
||||
#include "BluetoothCommon.h"
|
||||
#include <mozilla/ipc/UnixSocket.h>
|
||||
|
||||
BEGIN_BLUETOOTH_NAMESPACE
|
||||
|
||||
class BluetoothUnixSocketConnector : public mozilla::ipc::UnixSocketConnector
|
||||
{
|
||||
public:
|
||||
BluetoothUnixSocketConnector(BluetoothSocketType aType, int aChannel,
|
||||
bool aAuth, bool aEncrypt);
|
||||
virtual ~BluetoothUnixSocketConnector()
|
||||
{}
|
||||
virtual int Create() MOZ_OVERRIDE;
|
||||
virtual bool ConnectInternal(int aFd, const char* aAddress) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
BluetoothSocketType mType;
|
||||
int mChannel;
|
||||
bool mAuth;
|
||||
bool mEncrypt;
|
||||
};
|
||||
|
||||
END_BLUETOOTH_NAMESPACE
|
||||
|
||||
#endif
|
|
@ -51,6 +51,7 @@ CPPSRCS += \
|
|||
BluetoothChild.cpp \
|
||||
BluetoothParent.cpp \
|
||||
BluetoothServiceChildProcess.cpp \
|
||||
BluetoothUnixSocketConnector.cpp \
|
||||
$(NULL)
|
||||
|
||||
XPIDLSRCS = \
|
||||
|
|
|
@ -203,23 +203,16 @@ BluetoothServiceChildProcess::RemoveDeviceInternal(
|
|||
|
||||
nsresult
|
||||
BluetoothServiceChildProcess::GetSocketViaService(
|
||||
const nsAString& aObjectPath,
|
||||
const nsAString& aService,
|
||||
int aType,
|
||||
bool aAuth,
|
||||
bool aEncrypt,
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
const nsAString& aObjectPath,
|
||||
const nsAString& aService,
|
||||
BluetoothSocketType aType,
|
||||
bool aAuth,
|
||||
bool aEncrypt,
|
||||
mozilla::ipc::UnixSocketConsumer* aConsumer,
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
MOZ_NOT_REACHED("Implement me!");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothServiceChildProcess::CloseSocket(int aFd,
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
MOZ_NOT_REACHED("Implement me!");
|
||||
return false;
|
||||
MOZ_NOT_REACHED("This should never be called!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
#include "BluetoothService.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
class UnixSocketConsumer;
|
||||
}
|
||||
namespace dom {
|
||||
namespace bluetooth {
|
||||
|
||||
|
@ -86,14 +89,12 @@ public:
|
|||
virtual nsresult
|
||||
GetSocketViaService(const nsAString& aObjectPath,
|
||||
const nsAString& aService,
|
||||
int aType,
|
||||
BluetoothSocketType aType,
|
||||
bool aAuth,
|
||||
bool aEncrypt,
|
||||
mozilla::ipc::UnixSocketConsumer* aConsumer,
|
||||
BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
CloseSocket(int aFd, BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
SetPinCodeInternal(const nsAString& aDeviceAddress,
|
||||
const nsAString& aPinCode,
|
||||
|
@ -108,7 +109,7 @@ public:
|
|||
SetPairingConfirmationInternal(const nsAString& aDeviceAddress,
|
||||
bool aConfirm,
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
MOZ_OVERRIDE;
|
||||
MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
SetAuthorizationInternal(const nsAString& aDeviceAddress,
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "BluetoothDBusService.h"
|
||||
#include "BluetoothServiceUuid.h"
|
||||
#include "BluetoothReplyRunnable.h"
|
||||
#include "BluetoothUnixSocketConnector.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <dbus/dbus.h>
|
||||
|
@ -29,7 +30,7 @@
|
|||
#include "nsThreadUtils.h"
|
||||
#include "nsDebug.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "mozilla/ipc/Socket.h"
|
||||
#include "mozilla/ipc/UnixSocket.h"
|
||||
#include "mozilla/ipc/DBusThread.h"
|
||||
#include "mozilla/ipc/DBusUtils.h"
|
||||
#include "mozilla/ipc/RawDBusConnection.h"
|
||||
|
@ -1156,9 +1157,19 @@ EventFilter(DBusConnection* aConn, DBusMessage* aMsg, void* aData)
|
|||
// a dict value. After we parse out the properties, we need to go back
|
||||
// and add the address to the ipdl dict we've created to make sure we
|
||||
// have all of the information to correctly build the device.
|
||||
nsString addrstr = NS_ConvertUTF8toUTF16(addr);
|
||||
nsString path = GetObjectPathFromAddress(signalPath, addrstr);
|
||||
|
||||
v.get_ArrayOfBluetoothNamedValue()
|
||||
.AppendElement(BluetoothNamedValue(NS_LITERAL_STRING("Address"),
|
||||
NS_ConvertUTF8toUTF16(addr)));
|
||||
addrstr));
|
||||
|
||||
// We also need to create a path for the device, to make sure we know
|
||||
// where to access it later.
|
||||
v.get_ArrayOfBluetoothNamedValue()
|
||||
.AppendElement(BluetoothNamedValue(NS_LITERAL_STRING("Path"),
|
||||
path));
|
||||
|
||||
}
|
||||
} else {
|
||||
errorStr.AssignLiteral("DBus device found message structure not as expected!");
|
||||
|
@ -1571,8 +1582,15 @@ public:
|
|||
// for agent events "RequestConfirmation", "RequestPinCode", and "RequestPasskey"
|
||||
InfallibleTArray<BluetoothNamedValue> parameters = v.get_ArrayOfBluetoothNamedValue();
|
||||
|
||||
// For consistency, append path
|
||||
nsString path = parameters[0].value();
|
||||
BluetoothNamedValue pathprop;
|
||||
pathprop.name().AssignLiteral("Path");
|
||||
pathprop.value() = path;
|
||||
parameters.AppendElement(pathprop);
|
||||
|
||||
// Replace object path with device address
|
||||
nsString address = GetAddressFromObjectPath(parameters[0].value());
|
||||
nsString address = GetAddressFromObjectPath(path);
|
||||
parameters[0].value() = address;
|
||||
|
||||
uint8_t i;
|
||||
|
@ -1833,6 +1851,9 @@ GetDeviceServiceChannel(const nsAString& aObjectPath,
|
|||
// This is a blocking call, should not be run on main thread.
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
// GetServiceAttributeValue only exists in android's bluez dbus binding
|
||||
// implementation
|
||||
nsCString tempPattern = NS_ConvertUTF16toUTF8(aPattern);
|
||||
const char* pattern = tempPattern.get();
|
||||
|
||||
|
@ -1845,6 +1866,11 @@ GetDeviceServiceChannel(const nsAString& aObjectPath,
|
|||
DBUS_TYPE_INVALID);
|
||||
|
||||
return reply ? dbus_returns_int32(reply) : -1;
|
||||
#else
|
||||
// FIXME/Bug 793977 qdot: Just return something for desktop, until we have a
|
||||
// parser for the GetServiceAttributes xml block
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -2146,12 +2172,14 @@ class CreateBluetoothSocketRunnable : public nsRunnable
|
|||
{
|
||||
public:
|
||||
CreateBluetoothSocketRunnable(BluetoothReplyRunnable* aRunnable,
|
||||
UnixSocketConsumer* aConsumer,
|
||||
const nsAString& aObjectPath,
|
||||
const nsAString& aServiceUUID,
|
||||
int aType,
|
||||
BluetoothSocketType aType,
|
||||
bool aAuth,
|
||||
bool aEncrypt)
|
||||
: mRunnable(dont_AddRef(aRunnable)),
|
||||
mConsumer(aConsumer),
|
||||
mObjectPath(aObjectPath),
|
||||
mServiceUUID(aServiceUUID),
|
||||
mType(aType),
|
||||
|
@ -2168,18 +2196,16 @@ public:
|
|||
|
||||
nsString address = GetAddressFromObjectPath(mObjectPath);
|
||||
int channel = GetDeviceServiceChannel(mObjectPath, mServiceUUID, 0x0004);
|
||||
int fd = mozilla::ipc::GetNewSocket(mType, NS_ConvertUTF16toUTF8(address).get(),
|
||||
channel, mAuth, mEncrypt);
|
||||
BluetoothValue v;
|
||||
nsString replyError;
|
||||
if (fd < 0) {
|
||||
BluetoothUnixSocketConnector c(mType, channel, mAuth, mEncrypt);
|
||||
if (!mConsumer->ConnectSocket(c, NS_ConvertUTF16toUTF8(address).get())) {
|
||||
replyError.AssignLiteral("SocketConnectionError");
|
||||
DispatchBluetoothReply(mRunnable, v, replyError);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
v = (uint32_t)fd;
|
||||
|
||||
// Bluetooth value needs to be set to something to succeed.
|
||||
v = true;
|
||||
DispatchBluetoothReply(mRunnable, v, replyError);
|
||||
|
||||
return NS_OK;
|
||||
|
@ -2187,9 +2213,10 @@ public:
|
|||
|
||||
private:
|
||||
nsRefPtr<BluetoothReplyRunnable> mRunnable;
|
||||
nsRefPtr<UnixSocketConsumer> mConsumer;
|
||||
nsString mObjectPath;
|
||||
nsString mServiceUUID;
|
||||
int mType;
|
||||
BluetoothSocketType mType;
|
||||
bool mAuth;
|
||||
bool mEncrypt;
|
||||
};
|
||||
|
@ -2197,9 +2224,10 @@ private:
|
|||
nsresult
|
||||
BluetoothDBusService::GetSocketViaService(const nsAString& aObjectPath,
|
||||
const nsAString& aService,
|
||||
int aType,
|
||||
BluetoothSocketType aType,
|
||||
bool aAuth,
|
||||
bool aEncrypt,
|
||||
mozilla::ipc::UnixSocketConsumer* aConsumer,
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Must be called from main thread!");
|
||||
|
@ -2209,7 +2237,9 @@ BluetoothDBusService::GetSocketViaService(const nsAString& aObjectPath,
|
|||
}
|
||||
nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
|
||||
|
||||
nsRefPtr<nsRunnable> func(new CreateBluetoothSocketRunnable(runnable, aObjectPath,
|
||||
nsRefPtr<nsRunnable> func(new CreateBluetoothSocketRunnable(runnable,
|
||||
aConsumer,
|
||||
aObjectPath,
|
||||
aService, aType,
|
||||
aAuth, aEncrypt));
|
||||
if (NS_FAILED(mBluetoothCommandThread->Dispatch(func, NS_DISPATCH_NORMAL))) {
|
||||
|
@ -2221,53 +2251,3 @@ BluetoothDBusService::GetSocketViaService(const nsAString& aObjectPath,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
class CloseBluetoothSocketRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
CloseBluetoothSocketRunnable(BluetoothReplyRunnable* aRunnable,
|
||||
int aFd)
|
||||
: mRunnable(dont_AddRef(aRunnable)),
|
||||
mFd(aFd)
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
Run()
|
||||
{
|
||||
BluetoothValue v;
|
||||
nsString replyError;
|
||||
if (mozilla::ipc::CloseSocket(mFd) != 0) {
|
||||
replyError.AssignLiteral("SocketConnectionError");
|
||||
DispatchBluetoothReply(mRunnable, v, replyError);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
DispatchBluetoothReply(mRunnable, v, replyError);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<BluetoothReplyRunnable> mRunnable;
|
||||
int mFd;
|
||||
};
|
||||
|
||||
bool
|
||||
BluetoothDBusService::CloseSocket(int aFd, BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Must be called from main thread!");
|
||||
if (!mConnection || !gThreadConnection) {
|
||||
NS_ERROR("Bluetooth service not started yet!");
|
||||
return false;
|
||||
}
|
||||
nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
|
||||
|
||||
nsRefPtr<nsRunnable> func(new CloseBluetoothSocketRunnable(runnable, aFd));
|
||||
if (NS_FAILED(mBluetoothCommandThread->Dispatch(func, NS_DISPATCH_NORMAL))) {
|
||||
NS_WARNING("Cannot dispatch firmware loading task!");
|
||||
return false;
|
||||
}
|
||||
|
||||
runnable.forget();
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -70,13 +70,12 @@ public:
|
|||
virtual nsresult
|
||||
GetSocketViaService(const nsAString& aObjectPath,
|
||||
const nsAString& aService,
|
||||
int aType,
|
||||
BluetoothSocketType aType,
|
||||
bool aAuth,
|
||||
bool aEncrypt,
|
||||
mozilla::ipc::UnixSocketConsumer* aConsumer,
|
||||
BluetoothReplyRunnable* aRunnable);
|
||||
|
||||
virtual bool CloseSocket(int aFd, BluetoothReplyRunnable* aRunnable);
|
||||
|
||||
virtual nsresult
|
||||
CreatePairedDeviceInternal(const nsAString& aAdapterPath,
|
||||
const nsAString& aDeviceAddress,
|
||||
|
|
|
@ -19,7 +19,7 @@ using namespace mozilla::services;
|
|||
namespace mozilla {
|
||||
|
||||
bool
|
||||
AppProcessHasPermission(PBrowserParent* aActor, const char* aPermission)
|
||||
AssertAppProcessPermission(PBrowserParent* aActor, const char* aPermission)
|
||||
{
|
||||
if (!aActor) {
|
||||
NS_WARNING("Testing permissions for null actor");
|
||||
|
@ -46,12 +46,12 @@ AppProcessHasPermission(PBrowserParent* aActor, const char* aPermission)
|
|||
}
|
||||
|
||||
bool
|
||||
AppProcessHasPermission(PContentParent* aActor, const char* aPermission)
|
||||
AssertAppProcessPermission(PContentParent* aActor, const char* aPermission)
|
||||
{
|
||||
const InfallibleTArray<PBrowserParent*>& browsers =
|
||||
aActor->ManagedPBrowserParent();
|
||||
for (uint32_t i = 0; i < browsers.Length(); ++i) {
|
||||
if (AppProcessHasPermission(browsers[i], aPermission)) {
|
||||
if (AssertAppProcessPermission(browsers[i], aPermission)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -59,9 +59,9 @@ AppProcessHasPermission(PContentParent* aActor, const char* aPermission)
|
|||
}
|
||||
|
||||
bool
|
||||
AppProcessHasPermission(PHalParent* aActor, const char* aPermission)
|
||||
AssertAppProcessPermission(PHalParent* aActor, const char* aPermission)
|
||||
{
|
||||
return AppProcessHasPermission(aActor->Manager(), aPermission);
|
||||
return AssertAppProcessPermission(aActor->Manager(), aPermission);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
* 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 mozilla_Capabilities_h
|
||||
#define mozilla_Capabilities_h
|
||||
#ifndef mozilla_AppProcessPermissions_h
|
||||
#define mozilla_AppProcessPermissions_h
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -21,31 +21,34 @@ class PHalParent;
|
|||
|
||||
/**
|
||||
* Return true iff the specified browser has the specified capability.
|
||||
* If this returns false, the browser didn't have the permission and
|
||||
* will be killed.
|
||||
*/
|
||||
bool
|
||||
AppProcessHasPermissions(mozilla::dom::PBrowserParent* aActor,
|
||||
const char* aPermission);
|
||||
AssertAppProcessPermission(mozilla::dom::PBrowserParent* aActor,
|
||||
const char* aPermission);
|
||||
|
||||
/**
|
||||
* Return true iff any of the PBrowsers loaded in this content process
|
||||
* has the specified capability.
|
||||
* has the specified capability. If this returns false, the process
|
||||
* didn't have the permission and will be killed.
|
||||
*/
|
||||
bool
|
||||
AppProcessHasPermission(mozilla::dom::PContentParent* aActor,
|
||||
const char* aPermission);
|
||||
AssertAppProcessPermission(mozilla::dom::PContentParent* aActor,
|
||||
const char* aPermission);
|
||||
|
||||
bool
|
||||
AppProcessHasPermission(mozilla::hal_sandbox::PHalParent* aActor,
|
||||
const char* aPermission);
|
||||
AssertAppProcessPermission(mozilla::hal_sandbox::PHalParent* aActor,
|
||||
const char* aPermission);
|
||||
|
||||
// NB: when adding capability checks for other IPDL actors, please add
|
||||
// them to this file and have them delegate to the two functions above
|
||||
// as appropriate. For example,
|
||||
//
|
||||
// bool AppProcessHasCapability(PNeckoParent* aActor) {
|
||||
// return AppProcessHasCapability(aActor->Manager());
|
||||
// return AssertAppProcessPermission(aActor->Manager());
|
||||
// }
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_Capabilities_h
|
||||
#endif // mozilla_AppProcessPermissions_h
|
||||
|
|
|
@ -1450,7 +1450,7 @@ ContentParent::DeallocPExternalHelperApp(PExternalHelperAppParent* aService)
|
|||
PSmsParent*
|
||||
ContentParent::AllocPSms()
|
||||
{
|
||||
if (!AppProcessHasPermission(this, "sms")) {
|
||||
if (!AssertAppProcessPermission(this, "sms")) {
|
||||
return nullptr;
|
||||
}
|
||||
return new SmsParent();
|
||||
|
@ -1480,7 +1480,7 @@ PBluetoothParent*
|
|||
ContentParent::AllocPBluetooth()
|
||||
{
|
||||
#ifdef MOZ_B2G_BT
|
||||
if (!AppProcessHasPermission(this, "bluetooth")) {
|
||||
if (!AssertAppProcessPermission(this, "bluetooth")) {
|
||||
return nullptr;
|
||||
}
|
||||
return new mozilla::dom::bluetooth::BluetoothParent();
|
||||
|
|
|
@ -230,7 +230,8 @@ parent:
|
|||
* has already been cached (stickDocument=false).
|
||||
*/
|
||||
POfflineCacheUpdate(URIParams manifestURI, URIParams documentURI,
|
||||
nsCString clientID, bool stickDocument);
|
||||
bool isInBrowserElement, uint32_t appId,
|
||||
bool stickDocument);
|
||||
|
||||
sync PIndexedDB(nsCString asciiOrigin)
|
||||
returns (bool allowed);
|
||||
|
|
|
@ -1177,9 +1177,10 @@ TabChild::RecvActivateFrameEvent(const nsString& aType, const bool& capture)
|
|||
|
||||
POfflineCacheUpdateChild*
|
||||
TabChild::AllocPOfflineCacheUpdate(const URIParams& manifestURI,
|
||||
const URIParams& documentURI,
|
||||
const nsCString& clientID,
|
||||
const bool& stickDocument)
|
||||
const URIParams& documentURI,
|
||||
const bool& isInBrowserElement,
|
||||
const uint32_t& appId,
|
||||
const bool& stickDocument)
|
||||
{
|
||||
NS_RUNTIMEABORT("unused");
|
||||
return nullptr;
|
||||
|
|
|
@ -253,9 +253,11 @@ public:
|
|||
virtual PContentPermissionRequestChild* AllocPContentPermissionRequest(const nsCString& aType, const IPC::Principal& aPrincipal);
|
||||
virtual bool DeallocPContentPermissionRequest(PContentPermissionRequestChild* actor);
|
||||
|
||||
virtual POfflineCacheUpdateChild* AllocPOfflineCacheUpdate(const URIParams& manifestURI,
|
||||
virtual POfflineCacheUpdateChild* AllocPOfflineCacheUpdate(
|
||||
const URIParams& manifestURI,
|
||||
const URIParams& documentURI,
|
||||
const nsCString& clientID,
|
||||
const bool& isInBrowserElement,
|
||||
const uint32_t& appId,
|
||||
const bool& stickDocument);
|
||||
virtual bool DeallocPOfflineCacheUpdate(POfflineCacheUpdateChild* offlineCacheUpdate);
|
||||
|
||||
|
|
|
@ -1028,14 +1028,15 @@ TabParent::DeallocPRenderFrame(PRenderFrameParent* aFrame)
|
|||
mozilla::docshell::POfflineCacheUpdateParent*
|
||||
TabParent::AllocPOfflineCacheUpdate(const URIParams& aManifestURI,
|
||||
const URIParams& aDocumentURI,
|
||||
const nsCString& aClientID,
|
||||
const bool& isInBrowserElement,
|
||||
const uint32_t& appId,
|
||||
const bool& stickDocument)
|
||||
{
|
||||
nsRefPtr<mozilla::docshell::OfflineCacheUpdateParent> update =
|
||||
new mozilla::docshell::OfflineCacheUpdateParent();
|
||||
|
||||
nsresult rv = update->Schedule(aManifestURI, aDocumentURI, aClientID,
|
||||
stickDocument);
|
||||
nsresult rv = update->Schedule(aManifestURI, aDocumentURI,
|
||||
isInBrowserElement, appId, stickDocument);
|
||||
if (NS_FAILED(rv))
|
||||
return nullptr;
|
||||
|
||||
|
|
|
@ -181,7 +181,8 @@ public:
|
|||
virtual POfflineCacheUpdateParent* AllocPOfflineCacheUpdate(
|
||||
const URIParams& aManifestURI,
|
||||
const URIParams& aDocumentURI,
|
||||
const nsCString& aClientID,
|
||||
const bool& isInBrowserElement,
|
||||
const uint32_t& appId,
|
||||
const bool& stickDocument);
|
||||
virtual bool DeallocPOfflineCacheUpdate(POfflineCacheUpdateParent* actor);
|
||||
|
||||
|
|
|
@ -105,6 +105,7 @@ FocusedWindowedPluginWhileFullScreen=Exited full-screen because windowed plugin
|
|||
HTMLMultipartXHRWarning=HTML parsing in XMLHttpRequest is not supported for multipart responses.
|
||||
HTMLSyncXHRWarning=HTML parsing in XMLHttpRequest is not supported in the synchronous mode.
|
||||
InvalidRedirectChannelWarning=Unable to redirect to %S because the channel doesn't implement nsIWritablePropertyBag2.
|
||||
ReportOnlyCSPIgnored=Report-only CSP policy will be ignored because there are other non-report-only CSP policies applied.
|
||||
ResponseTypeSyncXHRWarning=Use of XMLHttpRequest's responseType attribute is no longer supported in the synchronous mode in window context.
|
||||
WithCredentialsSyncXHRWarning=Use of XMLHttpRequest's withCredentials attribute is no longer supported in the synchronous mode in window context.
|
||||
TimeoutSyncXHRWarning=Use of XMLHttpRequest's timeout attribute is not supported in the synchronous mode in window context.
|
||||
|
|
|
@ -18,6 +18,7 @@ XPIDLSRCS = \
|
|||
nsIDOMConnection.idl \
|
||||
nsIDOMUSSDReceivedEvent.idl \
|
||||
nsIDOMTCPSocket.idl \
|
||||
nsIDOMDataErrorEvent.idl \
|
||||
$(NULL)
|
||||
|
||||
ifdef MOZ_B2G_RIL
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
/* 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 "nsIDOMEvent.idl"
|
||||
|
||||
[scriptable, builtinclass, uuid(1cfc45ba-c5d4-11e1-b4c3-00265511db39)]
|
||||
interface nsIDOMDataErrorEvent : nsIDOMEvent
|
||||
{
|
||||
readonly attribute DOMString message;
|
||||
};
|
|
@ -12,7 +12,7 @@ interface nsIDOMMozMobileNetworkInfo;
|
|||
interface nsIDOMMozMobileCellInfo;
|
||||
interface nsIDOMMozIccManager;
|
||||
|
||||
[scriptable, builtinclass, uuid(d9009d90-a4b3-44fd-a592-42b09f330fe5)]
|
||||
[scriptable, builtinclass, uuid(c07309ee-a424-11e1-a75c-00265511db39)]
|
||||
interface nsIDOMMozMobileConnection : nsIDOMEventTarget
|
||||
{
|
||||
/**
|
||||
|
@ -239,6 +239,12 @@ interface nsIDOMMozMobileConnection : nsIDOMEventTarget
|
|||
* received.
|
||||
*/
|
||||
[implicit_jscontext] attribute jsval onussdreceived;
|
||||
|
||||
/**
|
||||
* The 'dataerror' event is notified whenever the data connection object
|
||||
* receives an error from the RIL
|
||||
*/
|
||||
[implicit_jscontext] attribute jsval ondataerror;
|
||||
};
|
||||
|
||||
[scriptable, uuid(5ea0e4a9-4684-40da-9930-8ebb61d187f3)]
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/* 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 "DataErrorEvent.h"
|
||||
#include "nsIDOMClassInfo.h"
|
||||
|
||||
DOMCI_DATA(DataErrorEvent, mozilla::dom::network::DataErrorEvent)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace network {
|
||||
|
||||
already_AddRefed<DataErrorEvent>
|
||||
DataErrorEvent::Create(nsAString& aMessage)
|
||||
{
|
||||
NS_ASSERTION(!aMessage.IsEmpty(), "Empty message!");
|
||||
|
||||
nsRefPtr<DataErrorEvent> event = new DataErrorEvent();
|
||||
|
||||
event->mMessage = aMessage;
|
||||
|
||||
return event.forget();
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(DataErrorEvent, nsDOMEvent)
|
||||
NS_IMPL_RELEASE_INHERITED(DataErrorEvent, nsDOMEvent)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(DataErrorEvent)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMDataErrorEvent)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DataErrorEvent)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
|
||||
|
||||
NS_IMETHODIMP
|
||||
DataErrorEvent::GetMessage(nsAString& aMessage)
|
||||
{
|
||||
aMessage.Assign(mMessage);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/* 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 mozilla_dom_network_dataerrorevent_h
|
||||
#define mozilla_dom_network_dataerrorevent_h
|
||||
|
||||
#include "nsIDOMDataErrorEvent.h"
|
||||
#include "nsDOMEvent.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace network {
|
||||
|
||||
class DataErrorEvent : public nsDOMEvent,
|
||||
public nsIDOMDataErrorEvent
|
||||
{
|
||||
nsString mMessage;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_FORWARD_TO_NSDOMEVENT
|
||||
NS_DECL_NSIDOMDATAERROREVENT
|
||||
|
||||
static already_AddRefed<DataErrorEvent>
|
||||
Create(nsAString& aMessage);
|
||||
|
||||
nsresult
|
||||
Dispatch(nsIDOMEventTarget* aTarget, const nsAString& aEventType)
|
||||
{
|
||||
NS_ASSERTION(aTarget, "Null pointer!");
|
||||
NS_ASSERTION(!aEventType.IsEmpty(), "Empty event type!");
|
||||
|
||||
nsresult rv = InitEvent(aEventType, false, false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = SetTrusted(true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsIDOMEvent* thisEvent =
|
||||
static_cast<nsDOMEvent*>(const_cast<DataErrorEvent*>(this));
|
||||
|
||||
bool dummy;
|
||||
rv = aTarget->DispatchEvent(thisEvent, &dummy);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
DataErrorEvent()
|
||||
: nsDOMEvent(nullptr, nullptr)
|
||||
{ }
|
||||
|
||||
~DataErrorEvent()
|
||||
{ }
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // mozilla_dom_network_dataerrorevent_h
|
|
@ -33,6 +33,7 @@ CPPSRCS = \
|
|||
Connection.cpp \
|
||||
Utils.cpp \
|
||||
USSDReceivedEvent.cpp \
|
||||
DataErrorEvent.cpp \
|
||||
$(NULL)
|
||||
|
||||
ifdef MOZ_B2G_RIL
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "nsDOMEvent.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "USSDReceivedEvent.h"
|
||||
#include "DataErrorEvent.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "IccManager.h"
|
||||
|
||||
|
@ -18,6 +19,7 @@
|
|||
#define CARDSTATECHANGE_EVENTNAME NS_LITERAL_STRING("cardstatechange")
|
||||
#define ICCINFOCHANGE_EVENTNAME NS_LITERAL_STRING("iccinfochange")
|
||||
#define USSDRECEIVED_EVENTNAME NS_LITERAL_STRING("ussdreceived")
|
||||
#define DATAERROR_EVENTNAME NS_LITERAL_STRING("dataerror")
|
||||
|
||||
DOMCI_DATA(MozMobileConnection, mozilla::dom::network::MobileConnection)
|
||||
|
||||
|
@ -30,6 +32,7 @@ const char* kDataChangedTopic = "mobile-connection-data-changed";
|
|||
const char* kCardStateChangedTopic = "mobile-connection-cardstate-changed";
|
||||
const char* kIccInfoChangedTopic = "mobile-connection-iccinfo-changed";
|
||||
const char* kUssdReceivedTopic = "mobile-connection-ussd-received";
|
||||
const char* kDataErrorTopic = "mobile-connection-data-error";
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(MobileConnection)
|
||||
|
||||
|
@ -57,6 +60,7 @@ NS_IMPL_EVENT_HANDLER(MobileConnection, iccinfochange)
|
|||
NS_IMPL_EVENT_HANDLER(MobileConnection, voicechange)
|
||||
NS_IMPL_EVENT_HANDLER(MobileConnection, datachange)
|
||||
NS_IMPL_EVENT_HANDLER(MobileConnection, ussdreceived)
|
||||
NS_IMPL_EVENT_HANDLER(MobileConnection, dataerror)
|
||||
|
||||
MobileConnection::MobileConnection()
|
||||
{
|
||||
|
@ -85,6 +89,7 @@ MobileConnection::Init(nsPIDOMWindow* aWindow)
|
|||
obs->AddObserver(this, kCardStateChangedTopic, false);
|
||||
obs->AddObserver(this, kIccInfoChangedTopic, false);
|
||||
obs->AddObserver(this, kUssdReceivedTopic, false);
|
||||
obs->AddObserver(this, kDataErrorTopic, false);
|
||||
|
||||
mIccManager = new icc::IccManager();
|
||||
mIccManager->Init(aWindow);
|
||||
|
@ -104,6 +109,7 @@ MobileConnection::Shutdown()
|
|||
obs->RemoveObserver(this, kCardStateChangedTopic);
|
||||
obs->RemoveObserver(this, kIccInfoChangedTopic);
|
||||
obs->RemoveObserver(this, kUssdReceivedTopic);
|
||||
obs->RemoveObserver(this, kDataErrorTopic);
|
||||
|
||||
if (mIccManager) {
|
||||
mIccManager->Shutdown();
|
||||
|
@ -147,7 +153,18 @@ MobileConnection::Observe(nsISupports* aSubject,
|
|||
nsresult rv =
|
||||
event->Dispatch(ToIDOMEventTarget(), USSDRECEIVED_EVENTNAME);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!strcmp(aTopic, kDataErrorTopic)) {
|
||||
nsString dataerror;
|
||||
dataerror.Assign(aData);
|
||||
nsRefPtr<DataErrorEvent> event = DataErrorEvent::Create(dataerror);
|
||||
NS_ASSERTION(event, "This should never fail!");
|
||||
|
||||
nsresult rv =
|
||||
event->Dispatch(ToIDOMEventTarget(), DATAERROR_EVENTNAME);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -773,8 +773,16 @@ nsDOMOfflineResourceList::CacheKeys()
|
|||
if (mCachedKeys)
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(GetOwner());
|
||||
nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(window);
|
||||
nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(webNav);
|
||||
|
||||
nsAutoCString groupID;
|
||||
mApplicationCacheService->BuildGroupID(
|
||||
mManifestURI, loadContext, groupID);
|
||||
|
||||
nsCOMPtr<nsIApplicationCache> appCache;
|
||||
mApplicationCacheService->GetActiveCache(mManifestSpec,
|
||||
mApplicationCacheService->GetActiveCache(groupID,
|
||||
getter_AddRefs(appCache));
|
||||
|
||||
if (!appCache) {
|
||||
|
|
|
@ -36,8 +36,7 @@ parent:
|
|||
__delete__();
|
||||
|
||||
Init(bool useDB, bool sessionOnly, bool isPrivate,
|
||||
nsCString domain, nsCString scopeDBKey,
|
||||
nsCString quotaDBKey, uint32_t storageType);
|
||||
nsCString scopeDBKey, nsCString quotaDBKey, uint32_t storageType);
|
||||
|
||||
sync GetKeys(bool callerSecure)
|
||||
returns (nsString[] keys);
|
||||
|
|
|
@ -83,21 +83,21 @@ StorageChild::InitRemote()
|
|||
ContentChild* child = ContentChild::GetSingleton();
|
||||
AddIPDLReference();
|
||||
child->SendPStorageConstructor(this, null_t());
|
||||
SendInit(mUseDB, mSessionOnly, mInPrivateBrowsing, mDomain, mScopeDBKey,
|
||||
SendInit(mUseDB, mSessionOnly, mInPrivateBrowsing, mScopeDBKey,
|
||||
mQuotaDBKey, mStorageType);
|
||||
}
|
||||
|
||||
void
|
||||
StorageChild::InitAsSessionStorage(nsIURI* aDomainURI, bool aPrivate)
|
||||
StorageChild::InitAsSessionStorage(nsIPrincipal* aPrincipal, bool aPrivate)
|
||||
{
|
||||
DOMStorageBase::InitAsSessionStorage(aDomainURI, aPrivate);
|
||||
DOMStorageBase::InitAsSessionStorage(aPrincipal, aPrivate);
|
||||
InitRemote();
|
||||
}
|
||||
|
||||
void
|
||||
StorageChild::InitAsLocalStorage(nsIURI* aDomainURI, bool aPrivate)
|
||||
StorageChild::InitAsLocalStorage(nsIPrincipal* aPrincipal, bool aPrivate)
|
||||
{
|
||||
DOMStorageBase::InitAsLocalStorage(aDomainURI, aPrivate);
|
||||
DOMStorageBase::InitAsLocalStorage(aPrincipal, aPrivate);
|
||||
InitRemote();
|
||||
}
|
||||
|
||||
|
@ -233,7 +233,7 @@ StorageChild::CloneFrom(bool aCallerSecure, DOMStorageBase* aThat)
|
|||
StorageClone clone(nullptr, other, aCallerSecure);
|
||||
AddIPDLReference();
|
||||
child->SendPStorageConstructor(this, clone);
|
||||
SendInit(mUseDB, mSessionOnly, mInPrivateBrowsing, mDomain,
|
||||
SendInit(mUseDB, mSessionOnly, mInPrivateBrowsing,
|
||||
mScopeDBKey, mQuotaDBKey, mStorageType);
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -26,8 +26,8 @@ public:
|
|||
StorageChild(nsDOMStorage* aOwner);
|
||||
StorageChild(nsDOMStorage* aOwner, StorageChild& aOther);
|
||||
|
||||
virtual void InitAsSessionStorage(nsIURI* aDomainURI, bool aPrivate);
|
||||
virtual void InitAsLocalStorage(nsIURI* aDomainURI, bool aPrivate);
|
||||
virtual void InitAsSessionStorage(nsIPrincipal* aPrincipal, bool aPrivate);
|
||||
virtual void InitAsLocalStorage(nsIPrincipal* aPrincipal, bool aPrivate);
|
||||
|
||||
virtual bool CacheStoragePermissions();
|
||||
|
||||
|
|
|
@ -30,12 +30,11 @@ bool
|
|||
StorageParent::RecvInit(const bool& aUseDB,
|
||||
const bool& aSessionOnly,
|
||||
const bool& aPrivate,
|
||||
const nsCString& aDomain,
|
||||
const nsCString& aScopeDBKey,
|
||||
const nsCString& aQuotaDBKey,
|
||||
const uint32_t& aStorageType)
|
||||
{
|
||||
mStorage->InitFromChild(aUseDB, aSessionOnly, aPrivate, aDomain,
|
||||
mStorage->InitFromChild(aUseDB, aSessionOnly, aPrivate,
|
||||
aScopeDBKey, aQuotaDBKey,
|
||||
aStorageType);
|
||||
return true;
|
||||
|
|
|
@ -45,7 +45,6 @@ private:
|
|||
bool RecvInit(const bool& aUseDB,
|
||||
const bool& aSessionOnly,
|
||||
const bool& aPrivate,
|
||||
const nsCString& aDomain,
|
||||
const nsCString& aScopeDBKey,
|
||||
const nsCString& aQuotaDBKey,
|
||||
const uint32_t& aStorageType);
|
||||
|
|
|
@ -59,38 +59,6 @@ static const char kStorageEnabled[] = "dom.storage.enabled";
|
|||
static const char kCookiesBehavior[] = "network.cookie.cookieBehavior";
|
||||
static const char kCookiesLifetimePolicy[] = "network.cookie.lifetimePolicy";
|
||||
|
||||
// The URI returned is the innermost URI that should be used for
|
||||
// security-check-like stuff. aHost is its hostname, correctly canonicalized.
|
||||
static nsresult
|
||||
GetPrincipalURIAndHost(nsIPrincipal* aPrincipal, nsIURI** aURI, nsCString& aHost)
|
||||
{
|
||||
nsresult rv = aPrincipal->GetDomain(aURI);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!*aURI) {
|
||||
rv = aPrincipal->GetURI(aURI);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
if (!*aURI) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(*aURI);
|
||||
if (!innerURI) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
rv = innerURI->GetAsciiHost(aHost);
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
innerURI.swap(*aURI);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// Helper that tells us whether the caller is secure or not.
|
||||
//
|
||||
|
@ -459,7 +427,6 @@ DOMStorageBase::DOMStorageBase(DOMStorageBase& aThat)
|
|||
: mStorageType(aThat.mStorageType)
|
||||
, mUseDB(false) // Clones don't use the DB
|
||||
, mSessionOnly(true)
|
||||
, mDomain(aThat.mDomain)
|
||||
, mScopeDBKey(aThat.mScopeDBKey)
|
||||
, mQuotaDBKey(aThat.mQuotaDBKey)
|
||||
, mInPrivateBrowsing(aThat.mInPrivateBrowsing)
|
||||
|
@ -467,15 +434,9 @@ DOMStorageBase::DOMStorageBase(DOMStorageBase& aThat)
|
|||
}
|
||||
|
||||
void
|
||||
DOMStorageBase::InitAsSessionStorage(nsIURI* aDomainURI, bool aPrivate)
|
||||
DOMStorageBase::InitAsSessionStorage(nsIPrincipal* aPrincipal, bool aPrivate)
|
||||
{
|
||||
// No need to check for a return value. If this would fail we would not get
|
||||
// here as we call GetPrincipalURIAndHost (nsDOMStorage.cpp:88) from
|
||||
// nsDOMStorage::CanUseStorage before we query the storage manager for a new
|
||||
// sessionStorage. It calls GetAsciiHost on innermost URI. If it fails, we
|
||||
// won't get to InitAsSessionStorage.
|
||||
aDomainURI->GetAsciiHost(mDomain);
|
||||
|
||||
MOZ_ASSERT(mQuotaDBKey.IsEmpty());
|
||||
mUseDB = false;
|
||||
mScopeDBKey.Truncate();
|
||||
mStorageType = nsPIDOMStorage::SessionStorage;
|
||||
|
@ -483,18 +444,9 @@ DOMStorageBase::InitAsSessionStorage(nsIURI* aDomainURI, bool aPrivate)
|
|||
}
|
||||
|
||||
void
|
||||
DOMStorageBase::InitAsLocalStorage(nsIURI* aDomainURI,
|
||||
bool aPrivate)
|
||||
DOMStorageBase::InitAsLocalStorage(nsIPrincipal* aPrincipal, bool aPrivate)
|
||||
{
|
||||
// No need to check for a return value. If this would fail we would not get
|
||||
// here as we call GetPrincipalURIAndHost (nsDOMStorage.cpp:88) from
|
||||
// nsDOMStorage::CanUseStorage before we query the storage manager for a new
|
||||
// localStorage. It calls GetAsciiHost on innermost URI. If it fails, we won't
|
||||
// get to InitAsLocalStorage. Actually, mDomain will get replaced with
|
||||
// mPrincipal in bug 455070. It is not even used for localStorage.
|
||||
aDomainURI->GetAsciiHost(mDomain);
|
||||
|
||||
nsDOMStorageDBWrapper::CreateScopeDBKey(aDomainURI, mScopeDBKey);
|
||||
nsDOMStorageDBWrapper::CreateScopeDBKey(aPrincipal, mScopeDBKey);
|
||||
|
||||
// XXX Bug 357323, we have to solve the issue how to define
|
||||
// origin for file URLs. In that case CreateOriginScopeDBKey
|
||||
|
@ -502,7 +454,7 @@ DOMStorageBase::InitAsLocalStorage(nsIURI* aDomainURI,
|
|||
// in that case because it produces broken entries w/o owner.
|
||||
mUseDB = !mScopeDBKey.IsEmpty();
|
||||
|
||||
nsDOMStorageDBWrapper::CreateQuotaDBKey(mDomain, mQuotaDBKey);
|
||||
nsDOMStorageDBWrapper::CreateQuotaDBKey(aPrincipal, mQuotaDBKey);
|
||||
mStorageType = nsPIDOMStorage::LocalStorage;
|
||||
mInPrivateBrowsing = aPrivate;
|
||||
}
|
||||
|
@ -589,7 +541,6 @@ DOMStorageImpl::InitDB()
|
|||
void
|
||||
DOMStorageImpl::InitFromChild(bool aUseDB,
|
||||
bool aSessionOnly, bool aPrivate,
|
||||
const nsACString& aDomain,
|
||||
const nsACString& aScopeDBKey,
|
||||
const nsACString& aQuotaDBKey,
|
||||
uint32_t aStorageType)
|
||||
|
@ -597,7 +548,6 @@ DOMStorageImpl::InitFromChild(bool aUseDB,
|
|||
mUseDB = aUseDB;
|
||||
mSessionOnly = aSessionOnly;
|
||||
mInPrivateBrowsing = aPrivate;
|
||||
mDomain = aDomain;
|
||||
mScopeDBKey = aScopeDBKey;
|
||||
mQuotaDBKey = aQuotaDBKey;
|
||||
mStorageType = static_cast<nsPIDOMStorage::nsDOMStorageType>(aStorageType);
|
||||
|
@ -609,19 +559,6 @@ DOMStorageImpl::SetSessionOnly(bool aSessionOnly)
|
|||
mSessionOnly = aSessionOnly;
|
||||
}
|
||||
|
||||
void
|
||||
DOMStorageImpl::InitAsSessionStorage(nsIURI* aDomainURI, bool aPrivate)
|
||||
{
|
||||
DOMStorageBase::InitAsSessionStorage(aDomainURI, aPrivate);
|
||||
}
|
||||
|
||||
void
|
||||
DOMStorageImpl::InitAsLocalStorage(nsIURI* aDomainURI,
|
||||
bool aPrivate)
|
||||
{
|
||||
DOMStorageBase::InitAsLocalStorage(aDomainURI, aPrivate);
|
||||
}
|
||||
|
||||
bool
|
||||
DOMStorageImpl::CacheStoragePermissions()
|
||||
{
|
||||
|
@ -1122,49 +1059,24 @@ nsDOMStorage::~nsDOMStorage()
|
|||
{
|
||||
}
|
||||
|
||||
static
|
||||
nsresult
|
||||
GetDomainURI(nsIPrincipal *aPrincipal, bool aIncludeDomain, nsIURI **_domain)
|
||||
{
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
|
||||
if (aIncludeDomain) {
|
||||
nsresult rv = aPrincipal->GetDomain(getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
if (!uri) {
|
||||
nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// Check if we really got any URI. System principal doesn't return a URI
|
||||
// instance and we would crash in NS_GetInnermostURI below.
|
||||
if (!uri)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(uri);
|
||||
if (!innerURI)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
innerURI.forget(_domain);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDOMStorage::InitAsSessionStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI,
|
||||
bool aPrivate)
|
||||
{
|
||||
nsCOMPtr<nsIURI> domainURI;
|
||||
nsresult rv = GetDomainURI(aPrincipal, true, getter_AddRefs(domainURI));
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!uri) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
mDocumentURI = aDocumentURI;
|
||||
mPrincipal = aPrincipal;
|
||||
|
||||
mStorageType = SessionStorage;
|
||||
|
||||
mStorageImpl->InitAsSessionStorage(domainURI, aPrivate);
|
||||
mStorageImpl->InitAsSessionStorage(mPrincipal, aPrivate);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1172,16 +1084,20 @@ nsresult
|
|||
nsDOMStorage::InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI,
|
||||
bool aPrivate)
|
||||
{
|
||||
nsCOMPtr<nsIURI> domainURI;
|
||||
nsresult rv = GetDomainURI(aPrincipal, false, getter_AddRefs(domainURI));
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!uri) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
mDocumentURI = aDocumentURI;
|
||||
mPrincipal = aPrincipal;
|
||||
|
||||
mStorageType = LocalStorage;
|
||||
|
||||
mStorageImpl->InitAsLocalStorage(domainURI, aPrivate);
|
||||
mStorageImpl->InitAsLocalStorage(aPrincipal, aPrivate);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1217,21 +1133,14 @@ nsDOMStorage::CanUseStorage(DOMStorageBase* aStorage /* = NULL */)
|
|||
// if subjectPrincipal were null we'd have returned after
|
||||
// IsCallerChrome().
|
||||
|
||||
nsCOMPtr<nsIURI> subjectURI;
|
||||
nsAutoCString unused;
|
||||
if (NS_FAILED(GetPrincipalURIAndHost(subjectPrincipal,
|
||||
getter_AddRefs(subjectURI),
|
||||
unused))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPermissionManager> permissionManager =
|
||||
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
|
||||
if (!permissionManager)
|
||||
return false;
|
||||
|
||||
uint32_t perm;
|
||||
permissionManager->TestPermission(subjectURI, kPermissionType, &perm);
|
||||
permissionManager->TestPermissionFromPrincipal(subjectPrincipal,
|
||||
kPermissionType, &perm);
|
||||
|
||||
if (perm == nsIPermissionManager::DENY_ACTION)
|
||||
return false;
|
||||
|
|
|
@ -109,8 +109,8 @@ public:
|
|||
DOMStorageBase();
|
||||
DOMStorageBase(DOMStorageBase&);
|
||||
|
||||
virtual void InitAsSessionStorage(nsIURI* aDomainURI, bool aPrivate);
|
||||
virtual void InitAsLocalStorage(nsIURI* aDomainURI, bool aPrivate);
|
||||
virtual void InitAsSessionStorage(nsIPrincipal* aPrincipal, bool aPrivate);
|
||||
virtual void InitAsLocalStorage(nsIPrincipal* aPrincipal, bool aPrivate);
|
||||
|
||||
virtual nsTArray<nsString>* GetKeys(bool aCallerSecure) = 0;
|
||||
virtual nsresult GetLength(bool aCallerSecure, uint32_t* aLength) = 0;
|
||||
|
@ -190,9 +190,6 @@ protected:
|
|||
// make sure this stays up to date.
|
||||
bool mSessionOnly;
|
||||
|
||||
// domain this store is associated with
|
||||
nsCString mDomain;
|
||||
|
||||
// keys are used for database queries.
|
||||
// see comments of the getters bellow.
|
||||
nsCString mScopeDBKey;
|
||||
|
@ -213,9 +210,6 @@ public:
|
|||
DOMStorageImpl(nsDOMStorage*, DOMStorageImpl&);
|
||||
~DOMStorageImpl();
|
||||
|
||||
virtual void InitAsSessionStorage(nsIURI* aDomainURI, bool aPrivate);
|
||||
virtual void InitAsLocalStorage(nsIURI* aDomainURI, bool aPrivate);
|
||||
|
||||
bool SessionOnly() {
|
||||
return mSessionOnly;
|
||||
}
|
||||
|
@ -281,7 +275,7 @@ private:
|
|||
// Cross-process storage implementations never have InitAs(Session|Local|Global)Storage
|
||||
// called, so the appropriate initialization needs to happen from the child.
|
||||
void InitFromChild(bool aUseDB, bool aSessionOnly,
|
||||
bool aPrivate, const nsACString& aDomain,
|
||||
bool aPrivate,
|
||||
const nsACString& aScopeDBKey,
|
||||
const nsACString& aQuotaDBKey,
|
||||
uint32_t aStorageType);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "nsIURL.h"
|
||||
#include "nsIVariant.h"
|
||||
#include "nsIEffectiveTLDService.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
#include "mozStorageCID.h"
|
||||
#include "mozStorageHelper.h"
|
||||
|
@ -19,6 +20,7 @@
|
|||
#include "mozIStorageFunction.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsIPrincipal.h"
|
||||
|
||||
void ReverseString(const nsCSubstring& source, nsCSubstring& result)
|
||||
{
|
||||
|
@ -226,37 +228,16 @@ nsDOMStorageDBWrapper::GetUsage(const nsACString& aDomain,
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsDOMStorageDBWrapper::CreateScopeDBKey(nsIURI* aUri, nsACString& aKey)
|
||||
nsDOMStorageDBWrapper::CreateScopeDBKey(nsIPrincipal* aPrincipal,
|
||||
nsACString& aKey)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = CreateReversedDomain(aUri, aKey);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
nsAutoCString scheme;
|
||||
rv = aUri->GetScheme(scheme);
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aKey.AppendLiteral(":");
|
||||
aKey.Append(scheme);
|
||||
|
||||
int32_t port = NS_GetRealPort(aUri);
|
||||
if (port != -1) {
|
||||
aKey.AppendLiteral(":");
|
||||
aKey.Append(nsPrintfCString("%d", port));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDOMStorageDBWrapper::CreateReversedDomain(nsIURI* aUri, nsACString& aKey)
|
||||
{
|
||||
nsresult rv;
|
||||
NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED);
|
||||
|
||||
nsAutoCString domainScope;
|
||||
rv = aUri->GetAsciiHost(domainScope);
|
||||
rv = uri->GetAsciiHost(domainScope);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (domainScope.IsEmpty()) {
|
||||
|
@ -264,25 +245,57 @@ nsDOMStorageDBWrapper::CreateReversedDomain(nsIURI* aUri, nsACString& aKey)
|
|||
// internally by our own redirector, we can trust them and use path as key.
|
||||
// if file:/// protocol, let's make the exact directory the domain
|
||||
bool isScheme = false;
|
||||
if ((NS_SUCCEEDED(aUri->SchemeIs("about", &isScheme)) && isScheme) ||
|
||||
(NS_SUCCEEDED(aUri->SchemeIs("moz-safe-about", &isScheme)) && isScheme)) {
|
||||
rv = aUri->GetPath(domainScope);
|
||||
if ((NS_SUCCEEDED(uri->SchemeIs("about", &isScheme)) && isScheme) ||
|
||||
(NS_SUCCEEDED(uri->SchemeIs("moz-safe-about", &isScheme)) && isScheme)) {
|
||||
rv = uri->GetPath(domainScope);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// While the host is always canonicalized to lowercase, the path is not,
|
||||
// thus need to force the casing.
|
||||
ToLowerCase(domainScope);
|
||||
}
|
||||
else if (NS_SUCCEEDED(aUri->SchemeIs("file", &isScheme)) && isScheme) {
|
||||
nsCOMPtr<nsIURL> url = do_QueryInterface(aUri, &rv);
|
||||
else if (NS_SUCCEEDED(uri->SchemeIs("file", &isScheme)) && isScheme) {
|
||||
nsCOMPtr<nsIURL> url = do_QueryInterface(uri, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = url->GetDirectory(domainScope);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
|
||||
rv = CreateReversedDomain(domainScope, aKey);
|
||||
nsAutoCString key;
|
||||
|
||||
rv = CreateReversedDomain(domainScope, key);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoCString scheme;
|
||||
rv = uri->GetScheme(scheme);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
key.Append(NS_LITERAL_CSTRING(":") + scheme);
|
||||
|
||||
int32_t port = NS_GetRealPort(uri);
|
||||
if (port != -1) {
|
||||
key.Append(nsPrintfCString(":%d", port));
|
||||
}
|
||||
|
||||
uint32_t appId;
|
||||
rv = aPrincipal->GetAppId(&appId);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool isInBrowserElement;
|
||||
rv = aPrincipal->GetIsInBrowserElement(&isInBrowserElement);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (appId == nsIScriptSecurityManager::NO_APP_ID && !isInBrowserElement) {
|
||||
aKey.Assign(key);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
aKey.Truncate();
|
||||
aKey.AppendInt(appId);
|
||||
aKey.Append(NS_LITERAL_CSTRING(":") + (isInBrowserElement ?
|
||||
NS_LITERAL_CSTRING("t") : NS_LITERAL_CSTRING("f")) +
|
||||
NS_LITERAL_CSTRING(":") + key);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -300,7 +313,7 @@ nsDOMStorageDBWrapper::CreateReversedDomain(const nsACString& aAsciiDomain,
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsDOMStorageDBWrapper::CreateQuotaDBKey(const nsACString& aAsciiDomain,
|
||||
nsDOMStorageDBWrapper::CreateQuotaDBKey(nsIPrincipal* aPrincipal,
|
||||
nsACString& aKey)
|
||||
{
|
||||
nsresult rv;
|
||||
|
@ -311,33 +324,39 @@ nsDOMStorageDBWrapper::CreateQuotaDBKey(const nsACString& aAsciiDomain,
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("http://") + aAsciiDomain);
|
||||
rv = aPrincipal->GetURI(getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED);
|
||||
|
||||
nsAutoCString eTLDplusOne;
|
||||
rv = eTLDService->GetBaseDomain(uri, 0, eTLDplusOne);
|
||||
if (NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS == rv) {
|
||||
// XXX bug 357323 - what to do for localhost/file exactly?
|
||||
eTLDplusOne = aAsciiDomain;
|
||||
rv = NS_OK;
|
||||
rv = uri->GetAsciiHost(eTLDplusOne);
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
CreateReversedDomain(eTLDplusOne, subdomainsDBKey);
|
||||
|
||||
aKey.Assign(subdomainsDBKey);
|
||||
return NS_OK;
|
||||
}
|
||||
uint32_t appId;
|
||||
rv = aPrincipal->GetAppId(&appId);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsresult
|
||||
nsDOMStorageDBWrapper::GetDomainFromScopeKey(const nsACString& aScope,
|
||||
nsACString& aDomain)
|
||||
{
|
||||
nsAutoCString reverseDomain, scope;
|
||||
scope = aScope;
|
||||
scope.Left(reverseDomain, scope.FindChar(':')-1);
|
||||
bool isInBrowserElement;
|
||||
rv = aPrincipal->GetIsInBrowserElement(&isInBrowserElement);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (appId == nsIScriptSecurityManager::NO_APP_ID && !isInBrowserElement) {
|
||||
aKey.Assign(subdomainsDBKey);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
aKey.Truncate();
|
||||
aKey.AppendInt(appId);
|
||||
aKey.Append(NS_LITERAL_CSTRING(":") + (isInBrowserElement ?
|
||||
NS_LITERAL_CSTRING("t") : NS_LITERAL_CSTRING("f")) +
|
||||
NS_LITERAL_CSTRING(":") + subdomainsDBKey);
|
||||
|
||||
ReverseString(reverseDomain, aDomain);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -173,7 +173,7 @@ public:
|
|||
* i.e. reverses the host, appends a dot, appends the schema
|
||||
* and a port number.
|
||||
*/
|
||||
static nsresult CreateScopeDBKey(nsIURI* aUri, nsACString& aKey);
|
||||
static nsresult CreateScopeDBKey(nsIPrincipal* aPrincipal, nsACString& aKey);
|
||||
|
||||
/**
|
||||
* Turns "http://foo.bar.com" to "moc.rab.oof.",
|
||||
|
@ -187,11 +187,19 @@ public:
|
|||
* i.e. extracts eTLD+1 from the host, reverses the result
|
||||
* and appends a dot.
|
||||
*/
|
||||
static nsresult CreateQuotaDBKey(const nsACString& aAsciiDomain,
|
||||
static nsresult CreateQuotaDBKey(nsIPrincipal* aPrincipal,
|
||||
nsACString& aKey);
|
||||
|
||||
static nsresult GetDomainFromScopeKey(const nsACString& aScope,
|
||||
nsACString& aDomain);
|
||||
/**
|
||||
* Turns "foo.bar.com" to "moc.rab.",
|
||||
* i.e. extracts eTLD+1 from the host, reverses the result
|
||||
* and appends a dot.
|
||||
*/
|
||||
static nsresult CreateQuotaDBKey(const nsACString& aDomain,
|
||||
nsACString& aKey)
|
||||
{
|
||||
return CreateReversedDomain(aDomain, aKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the temp table flush timer is running. This is called when we add
|
||||
|
|
|
@ -61,7 +61,8 @@ const RIL_IPC_MSG_NAMES = [
|
|||
"RIL:CancelUssd:Return:OK",
|
||||
"RIL:CancelUssd:Return:KO",
|
||||
"RIL:StkCommand",
|
||||
"RIL:StkSessionEnd"
|
||||
"RIL:StkSessionEnd",
|
||||
"RIL:DataError"
|
||||
];
|
||||
|
||||
const kVoiceChangedTopic = "mobile-connection-voice-changed";
|
||||
|
@ -71,6 +72,7 @@ const kIccInfoChangedTopic = "mobile-connection-iccinfo-changed";
|
|||
const kUssdReceivedTopic = "mobile-connection-ussd-received";
|
||||
const kStkCommandTopic = "icc-manager-stk-command";
|
||||
const kStkSessionEndTopic = "icc-manager-stk-session-end";
|
||||
const kDataErrorTopic = "mobile-connection-data-error";
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
"@mozilla.org/childprocessmessagemanager;1",
|
||||
|
@ -714,7 +716,11 @@ RILContentHelper.prototype = {
|
|||
break;
|
||||
case "RIL:StkSessionEnd":
|
||||
Services.obs.notifyObservers(null, kStkSessionEndTopic, null);
|
||||
break;
|
||||
break;
|
||||
case "RIL:DataError":
|
||||
this.updateConnectionInfo(msg.json, this.dataConnectionInfo);
|
||||
Services.obs.notifyObservers(null, kDataErrorTopic, msg.json.error);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -381,10 +381,7 @@ RadioInterfaceLayer.prototype = {
|
|||
this.updateDataConnection(message);
|
||||
break;
|
||||
case "datacallerror":
|
||||
// 3G Network revoked the data connection, possible unavailable APN
|
||||
debug("Received data registration error message. Failed APN " +
|
||||
this.dataCallSettings["apn"]);
|
||||
RILNetworkInterface.reset();
|
||||
this.handleDataCallError(message);
|
||||
break;
|
||||
case "signalstrengthchange":
|
||||
this.handleSignalStrengthChange(message);
|
||||
|
@ -645,6 +642,20 @@ RadioInterfaceLayer.prototype = {
|
|||
this.updateRILNetworkInterface();
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle data errors
|
||||
*/
|
||||
handleDataCallError: function handleDataCallError(message) {
|
||||
if (message.apn != this.dataCallSettings["apn"]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 3G Network revoked the data connection, possible unavailable APN
|
||||
RILNetworkInterface.reset();
|
||||
// Notify datacall error
|
||||
ppmm.broadcastAsyncMessage("RIL:DataError", message);
|
||||
},
|
||||
|
||||
handleSignalStrengthChange: function handleSignalStrengthChange(message) {
|
||||
let voiceInfo = this.rilContext.voice;
|
||||
// TODO CDMA, EVDO, LTE, etc. (see bug 726098)
|
||||
|
|
|
@ -1719,6 +1719,53 @@ RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_IMSI_UNKNOWN_IN_VLR] = GECKO_CA
|
|||
RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_IMEI_NOT_ACCEPTED] = GECKO_CALL_ERROR_DEVICE_NOT_ACCEPTED;
|
||||
RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_ERROR_UNSPECIFIED] = GECKO_CALL_ERROR_UNSPECIFIED;
|
||||
|
||||
const GECKO_DATACALL_ERROR_OPERATOR_BARRED = "OperatorBarredError";
|
||||
const GECKO_DATACALL_ERROR_INSUFFICIENT_RESOURCES = "InsufficientResourcesError";
|
||||
const GECKO_DATACALL_ERROR_MISSING_UKNOWN_APN = "MissingUnknownAPNError";
|
||||
const GECKO_DATACALL_ERROR_UNKNOWN_PDP_ADDRESS_TYPE = "UnknownPDPAddressTypeError";
|
||||
const GECKO_DATACALL_ERROR_USER_AUTHENTICATION = "UserAuthenticationError";
|
||||
const GECKO_DATACALL_ERROR_ACTIVATION_REJECT_GGSN = "ActivationRejectGGSNError";
|
||||
const GECKO_DATACALL_ERROR_ACTIVATION_REJECT_UNSPECIFIED = "ActivationRejectUnspecifiedError";
|
||||
const GECKO_DATACALL_ERROR_SERVICE_OPTION_NOT_SUPPORTED = "ServiceOptionNotSupportedError";
|
||||
const GECKO_DATACALL_ERROR_SERVICE_OPTION_NOT_SUBSCRIBED = "ServiceOptionNotSubscribedError";
|
||||
const GECKO_DATACALL_ERROR_SERVICE_OPTION_OUT_OF_ORDER = "ServiceOptionOutOfOrderError";
|
||||
const GECKO_DATACALL_ERROR_NSAPI_IN_USE = "NSAPIInUseError";
|
||||
const GECKO_DATACALL_ERROR_ONLY_IPV4_ALLOWED = "OnlyIPv4Error";
|
||||
const GECKO_DATACALL_ERROR_ONLY_IPV6_ALLOWED = "OnlyIPv6Error";
|
||||
const GECKO_DATACALL_ERROR_ONLY_SINGLE_BEARER_ALLOWED = "OnlySingleBearerAllowedError";
|
||||
const GECKO_DATACALL_ERROR_PROTOCOL_ERRORS = "ProtocolErrorsError";
|
||||
const GECKO_DATACALL_ERROR_VOICE_REGISTRATION_FAIL = "VoiceRegistrationFailError";
|
||||
const GECKO_DATACALL_ERROR_DATA_REGISTRATION_FAIL = "DataRegistrationFailError";
|
||||
const GECKO_DATACALL_ERROR_SIGNAL_LOST = "SignalLostError";
|
||||
const GECKO_DATACALL_ERROR_PREF_RADIO_TECH_CHANGED = "PrefRadioTechChangedError";
|
||||
const GECKO_DATACALL_ERROR_RADIO_POWER_OFF = "RadioPowerOffError";
|
||||
const GECKO_DATACALL_ERROR_TETHERED_CALL_ACTIVE = "TetheredCallActiveError";
|
||||
const GECKO_DATACALL_ERROR_UNSPECIFIED = "UnspecifiedError";
|
||||
|
||||
const RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR = {};
|
||||
RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_OPERATOR_BARRED] = GECKO_DATACALL_ERROR_OPERATOR_BARRED;
|
||||
RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_INSUFFICIENT_RESOURCES] = GECKO_DATACALL_ERROR_INSUFFICIENT_RESOURCES;
|
||||
RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_MISSING_UKNOWN_APN] = GECKO_DATACALL_ERROR_MISSING_UKNOWN_APN;
|
||||
RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_UNKNOWN_PDP_ADDRESS_TYPE] = GECKO_DATACALL_ERROR_UNKNOWN_PDP_ADDRESS_TYPE;
|
||||
RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_USER_AUTHENTICATION] = GECKO_DATACALL_ERROR_USER_AUTHENTICATION;
|
||||
RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_ACTIVATION_REJECT_GGSN] = GECKO_DATACALL_ERROR_ACTIVATION_REJECT_GGSN;
|
||||
RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_ACTIVATION_REJECT_UNSPECIFIED] = GECKO_DATACALL_ERROR_ACTIVATION_REJECT_UNSPECIFIED;
|
||||
RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_SERVICE_OPTION_NOT_SUPPORTED] = GECKO_DATACALL_ERROR_SERVICE_OPTION_NOT_SUPPORTED;
|
||||
RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED] = GECKO_DATACALL_ERROR_SERVICE_OPTION_NOT_SUBSCRIBED;
|
||||
RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_SERVICE_OPTION_OUT_OF_ORDER] = GECKO_DATACALL_ERROR_SERVICE_OPTION_OUT_OF_ORDER;
|
||||
RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_NSAPI_IN_USE] = GECKO_DATACALL_ERROR_NSAPI_IN_USE;
|
||||
RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_ONLY_IPV4_ALLOWED] = GECKO_DATACALL_ERROR_ONLY_IPV4_ALLOWED;
|
||||
RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_ONLY_IPV6_ALLOWED] = GECKO_DATACALL_ERROR_ONLY_IPV6_ALLOWED;
|
||||
RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_ONLY_SINGLE_BEARER_ALLOWED] = GECKO_DATACALL_ERROR_ONLY_SINGLE_BEARER_ALLOWED;
|
||||
RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_PROTOCOL_ERRORS] = GECKO_DATACALL_ERROR_PROTOCOL_ERRORS;
|
||||
RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_VOICE_REGISTRATION_FAIL] = GECKO_DATACALL_ERROR_VOICE_REGISTRATION_FAIL;
|
||||
RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_DATA_REGISTRATION_FAIL] = GECKO_DATACALL_ERROR_DATA_REGISTRATION_FAIL;
|
||||
RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_SIGNAL_LOST] = GECKO_DATACALL_ERROR_SIGNAL_LOST;
|
||||
RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_PREF_RADIO_TECH_CHANGED] = GECKO_DATACALL_ERROR_PREF_RADIO_TECH_CHANGED;
|
||||
RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_RADIO_POWER_OFF] = GECKO_DATACALL_ERROR_RADIO_POWER_OFF;
|
||||
RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_TETHERED_CALL_ACTIVE] = GECKO_DATACALL_ERROR_TETHERED_CALL_ACTIVE;
|
||||
RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_ERROR_UNSPECIFIED] = GECKO_DATACALL_ERROR_UNSPECIFIED;
|
||||
|
||||
const GECKO_RADIO_TECH = [
|
||||
null,
|
||||
"gprs",
|
||||
|
|
|
@ -2900,7 +2900,26 @@ let RIL = {
|
|||
}
|
||||
},
|
||||
|
||||
_sendDataCallError: function _sendDataCallError(message, errorCode) {
|
||||
message.rilMessageType = "datacallerror";
|
||||
if (errorCode == ERROR_GENERIC_FAILURE) {
|
||||
message.error = RIL_ERROR_TO_GECKO_ERROR[errorCode];
|
||||
} else {
|
||||
message.error = RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[errorCode];
|
||||
}
|
||||
this.sendDOMMessage(message);
|
||||
},
|
||||
|
||||
_processDataCallList: function _processDataCallList(datacalls, newDataCallOptions) {
|
||||
// Check for possible PDP errors: We check earlier because the datacall
|
||||
// can be removed if is the same as the current one.
|
||||
for each (let newDataCall in datacalls) {
|
||||
if (newDataCall.status != DATACALL_FAIL_NONE) {
|
||||
newDataCall.apn = newDataCallOptions.apn;
|
||||
this._sendDataCallError(newDataCall, newDataCall.status);
|
||||
}
|
||||
}
|
||||
|
||||
for each (let currentDataCall in this.currentDataCalls) {
|
||||
let updatedDataCall;
|
||||
if (datacalls) {
|
||||
|
@ -3705,8 +3724,8 @@ RIL.readSetupDataCall_v5 = function readSetupDataCall_v5(options) {
|
|||
|
||||
RIL[REQUEST_SETUP_DATA_CALL] = function REQUEST_SETUP_DATA_CALL(length, options) {
|
||||
if (options.rilRequestError) {
|
||||
options.rilMessageType = "datacallerror";
|
||||
this.sendDOMMessage(options);
|
||||
// On Data Call generic errors, we shall notify caller
|
||||
this._sendDataCallError(options, options.rilRequestError);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,12 +14,12 @@ function manifestUpdated()
|
|||
.getService(SpecialPowers.Ci.nsIApplicationCacheService);
|
||||
|
||||
var foreign2cache = appCacheService.chooseApplicationCache(
|
||||
"http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign2.html");
|
||||
"http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign2.html", OfflineTest.loadContext());
|
||||
|
||||
OfflineTest.ok(foreign2cache, "Foreign 2 cache present, chosen for foreign2.html");
|
||||
OfflineTest.is(foreign2cache.groupID, "http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign2.cacheManifest")
|
||||
OfflineTest.is(foreign2cache.manifestURI.asciiSpec, "http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign2.cacheManifest")
|
||||
|
||||
var foreign1cache = appCacheService.getActiveCache(
|
||||
var foreign1cache = OfflineTest.getActiveCache(
|
||||
"http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign1.cacheManifest");
|
||||
OfflineTest.ok(foreign1cache, "Foreign 1 cache loaded");
|
||||
foreign1cache.discard();
|
||||
|
@ -33,16 +33,16 @@ function onLoaded()
|
|||
var appCacheService = SpecialPowers.Components.classes["@mozilla.org/network/application-cache-service;1"]
|
||||
.getService(SpecialPowers.Ci.nsIApplicationCacheService);
|
||||
|
||||
var foreign1cache = appCacheService.getActiveCache(
|
||||
var foreign1cache = OfflineTest.getActiveCache(
|
||||
"http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign1.cacheManifest");
|
||||
OfflineTest.ok(foreign1cache, "Foreign 1 cache loaded");
|
||||
|
||||
var foreign2cache = appCacheService.getActiveCache(
|
||||
var foreign2cache = OfflineTest.getActiveCache(
|
||||
"http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign2.cacheManifest");
|
||||
OfflineTest.ok(!foreign2cache, "Foreign 2 cache not present");
|
||||
|
||||
foreign1cache = appCacheService.chooseApplicationCache(
|
||||
"http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign2.html");
|
||||
"http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign2.html", OfflineTest.loadContext());
|
||||
OfflineTest.ok(!foreign1cache, "foreign2.html not chosen from foreign1 cache");
|
||||
|
||||
try
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче