Merge last PGO-green changeset of mozilla-inbound to mozilla-central

This commit is contained in:
Ed Morley 2012-08-02 14:19:18 +01:00
commit 24117e18a9
215 changed files with 6151 additions and 1383 deletions

View File

@ -715,36 +715,22 @@ pref("gecko.handlerService.schemes.ircs.3.uriTemplate", "chrome://browser-region
pref("gecko.handlerService.allowRegisterFromDifferentHost", false);
#ifdef MOZ_SAFE_BROWSING
// Safe browsing does nothing unless this pref is set
pref("browser.safebrowsing.enabled", true);
// Prevent loading of pages identified as malware
pref("browser.safebrowsing.malware.enabled", true);
// Debug logging to error console
pref("browser.safebrowsing.debug", false);
// Non-enhanced mode (local url lists) URL list to check for updates
pref("browser.safebrowsing.provider.0.updateURL", "http://safebrowsing.clients.google.com/safebrowsing/downloads?client={moz:client}&appver={moz:version}&pver=2.2");
pref("browser.safebrowsing.updateURL", "http://safebrowsing.clients.google.com/safebrowsing/downloads?client=SAFEBROWSING_ID&appver=%VERSION%&pver=2.2");
pref("browser.safebrowsing.keyURL", "https://sb-ssl.google.com/safebrowsing/newkey?client=SAFEBROWSING_ID&appver=%VERSION%&pver=2.2");
pref("browser.safebrowsing.gethashURL", "http://safebrowsing.clients.google.com/safebrowsing/gethash?client=SAFEBROWSING_ID&appver=%VERSION%&pver=2.2");
pref("browser.safebrowsing.reportURL", "http://safebrowsing.clients.google.com/safebrowsing/report?");
pref("browser.safebrowsing.reportGenericURL", "http://%LOCALE%.phish-generic.mozilla.com/?hl=%LOCALE%");
pref("browser.safebrowsing.reportErrorURL", "http://%LOCALE%.phish-error.mozilla.com/?hl=%LOCALE%");
pref("browser.safebrowsing.reportPhishURL", "http://%LOCALE%.phish-report.mozilla.com/?hl=%LOCALE%");
pref("browser.safebrowsing.reportMalwareURL", "http://%LOCALE%.malware-report.mozilla.com/?hl=%LOCALE%");
pref("browser.safebrowsing.reportMalwareErrorURL", "http://%LOCALE%.malware-error.mozilla.com/?hl=%LOCALE%");
pref("browser.safebrowsing.dataProvider", 0);
// Does the provider name need to be localizable?
pref("browser.safebrowsing.provider.0.name", "Google");
pref("browser.safebrowsing.provider.0.keyURL", "https://sb-ssl.google.com/safebrowsing/newkey?client={moz:client}&appver={moz:version}&pver=2.2");
pref("browser.safebrowsing.provider.0.reportURL", "http://safebrowsing.clients.google.com/safebrowsing/report?");
pref("browser.safebrowsing.provider.0.gethashURL", "http://safebrowsing.clients.google.com/safebrowsing/gethash?client={moz:client}&appver={moz:version}&pver=2.2");
// HTML report pages
pref("browser.safebrowsing.provider.0.reportGenericURL", "http://{moz:locale}.phish-generic.mozilla.com/?hl={moz:locale}");
pref("browser.safebrowsing.provider.0.reportErrorURL", "http://{moz:locale}.phish-error.mozilla.com/?hl={moz:locale}");
pref("browser.safebrowsing.provider.0.reportPhishURL", "http://{moz:locale}.phish-report.mozilla.com/?hl={moz:locale}");
pref("browser.safebrowsing.provider.0.reportMalwareURL", "http://{moz:locale}.malware-report.mozilla.com/?hl={moz:locale}");
pref("browser.safebrowsing.provider.0.reportMalwareErrorURL", "http://{moz:locale}.malware-error.mozilla.com/?hl={moz:locale}");
// FAQ URLs
pref("browser.safebrowsing.warning.infoURL", "http://www.mozilla.com/%LOCALE%/firefox/phishing-protection/");
pref("browser.geolocation.warning.infoURL", "http://www.mozilla.com/%LOCALE%/firefox/geolocation/");
pref("browser.safebrowsing.malware.reportURL", "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site=");
// Name of the about: page contributed by safebrowsing to handle display of error
// pages on phishing/malware hits. (bug 399233)
@ -766,12 +752,10 @@ pref("urlclassifier.updatecachemax", 41943040);
// Maximum size of the sqlite3 cache for lookups, in bytes
pref("urlclassifier.lookupcachemax", 1048576);
// URL for checking the reason for a malware warning.
pref("browser.safebrowsing.malware.reportURL", "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site=");
#endif
pref("browser.geolocation.warning.infoURL", "http://www.mozilla.com/%LOCALE%/firefox/geolocation/");
pref("browser.EULA.version", 3);
pref("browser.rights.version", 3);
pref("browser.rights.3.shown", false);

View File

@ -1,4 +1,3 @@
#
# 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/.
@ -13,8 +12,12 @@ include $(DEPTH)/config/autoconf.mk
TEST_DIRS += content/test
# Normally the "client ID" sent in updates is appinfo.name, but for
# official Firefox releases from Mozilla we use a special identifier.
ifdef MOZILLA_OFFICIAL
DEFINES += -DOFFICIAL_BUILD=1
ifdef MOZ_PHOENIX
DEFINES += -DUSE_HISTORIC_SAFEBROWSING_ID=1
endif
endif
EXTRA_PP_JS_MODULES = \

View File

@ -34,20 +34,9 @@ var SafeBrowsing = {
Services.prefs.addObserver("browser.safebrowsing", this.readPrefs, false);
this.readPrefs();
this.initProviderURLs();
// Initialize the list manager
// Register our two types of tables, and add custom Mozilla entries
let listManager = Cc["@mozilla.org/url-classifier/listmanager;1"].
getService(Ci.nsIUrlListManager);
listManager.setUpdateUrl(this.updateURL);
// setKeyUrl has the side effect of fetching a key from the server.
// This shouldn't happen if anti-phishing/anti-malware is disabled.
if (this.phishingEnabled || this.malwareEnabled)
listManager.setKeyUrl(this.keyURL);
listManager.setGethashUrl(this.gethashURL);
// Register our two types of tables
listManager.registerTable(phishingList, false);
listManager.registerTable(malwareList, false);
this.addMozEntries();
@ -63,11 +52,11 @@ var SafeBrowsing = {
phishingEnabled: false,
malwareEnabled: false,
provName: null,
updateURL: null,
keyURL: null,
reportURL: null,
gethashURL: null,
reportURL: null,
reportGenericURL: null,
reportErrorURL: null,
reportPhishURL: null,
@ -86,6 +75,7 @@ var SafeBrowsing = {
debug = Services.prefs.getBoolPref("browser.safebrowsing.debug");
this.phishingEnabled = Services.prefs.getBoolPref("browser.safebrowsing.enabled");
this.malwareEnabled = Services.prefs.getBoolPref("browser.safebrowsing.malware.enabled");
this.updateProviderURLs();
// XXX The listManager backend gets confused if this is called before the
// lists are registered. So only call it here when a pref changes, and not
@ -95,67 +85,42 @@ var SafeBrowsing = {
},
initProviderURLs: function() {
log("initializing provider URLs");
// XXX remove this as obsolete?
let provID = Services.prefs.getIntPref("browser.safebrowsing.dataProvider");
if (provID != 0) {
Cu.reportError("unknown safebrowsing provider ID " + provID);
return;
}
let basePref = "browser.safebrowsing.provider.0.";
this.provName = Services.prefs.getCharPref(basePref + "name");
// Urls used to get data from a provider
this.updateURL = this.getUrlPref(basePref + "updateURL");
this.keyURL = this.getUrlPref(basePref + "keyURL");
this.reportURL = this.getUrlPref(basePref + "reportURL");
this.gethashURL = this.getUrlPref(basePref + "gethashURL");
// Urls to HTML report pages
this.reportGenericURL = this.getUrlPref(basePref + "reportGenericURL");
this.reportErrorURL = this.getUrlPref(basePref + "reportErrorURL");
this.reportPhishURL = this.getUrlPref(basePref + "reportPhishURL");
this.reportMalwareURL = this.getUrlPref(basePref + "reportMalwareURL")
this.reportMalwareErrorURL = this.getUrlPref(basePref + "reportMalwareErrorURL")
},
getUrlPref: function(prefName) {
let MOZ_OFFICIAL_BUILD = false;
#ifdef OFFICIAL_BUILD
MOZ_OFFICIAL_BUILD = true;
updateProviderURLs: function() {
#ifdef USE_HISTORIC_SAFEBROWSING_ID
let clientID = "navclient-auto-ffox";
#else
let clientID = Services.appinfo.name;
#endif
let url = Services.prefs.getCharPref(prefName);
log("initializing safe browsing URLs");
let basePref = "browser.safebrowsing.";
let clientName = MOZ_OFFICIAL_BUILD ? "navclient-auto-ffox" : Services.appinfo.name;
let clientVersion = Services.appinfo.version;
// Urls to HTML report pages
this.reportURL = Services.urlFormatter.formatURLPref(basePref + "reportURL");
this.reportGenericURL = Services.urlFormatter.formatURLPref(basePref + "reportGenericURL");
this.reportErrorURL = Services.urlFormatter.formatURLPref(basePref + "reportErrorURL");
this.reportPhishURL = Services.urlFormatter.formatURLPref(basePref + "reportPhishURL");
this.reportMalwareURL = Services.urlFormatter.formatURLPref(basePref + "reportMalwareURL");
this.reportMalwareErrorURL = Services.urlFormatter.formatURLPref(basePref + "reportMalwareErrorURL");
// Parameter substitution
// XXX: we should instead use nsIURLFormatter here.
url = url.replace(/\{moz:locale\}/g, this.getLocale());
url = url.replace(/\{moz:client\}/g, clientName);
url = url.replace(/\{moz:buildid\}/g, Services.appinfo.appBuildID);
url = url.replace(/\{moz:version\}/g, clientVersion);
// Urls used to update DB
this.updateURL = Services.urlFormatter.formatURLPref(basePref + "updateURL");
this.keyURL = Services.urlFormatter.formatURLPref(basePref + "keyURL");
this.gethashURL = Services.urlFormatter.formatURLPref(basePref + "gethashURL");
log(prefName, "is", url);
return url;
},
this.updateURL = this.updateURL.replace("SAFEBROWSING_ID", clientID);
this.keyURL = this.keyURL.replace("SAFEBROWSING_ID", clientID);
this.gethashURL = this.gethashURL.replace("SAFEBROWSING_ID", clientID);
let listManager = Cc["@mozilla.org/url-classifier/listmanager;1"].
getService(Ci.nsIUrlListManager);
getLocale: function() {
const localePref = "general.useragent.locale";
let locale = Services.prefs.getCharPref(localePref);
try {
// Dumb. This API only works if pref is localized or has a user value.
locale = Services.prefs.getComplexValue(localePref, Ci.nsIPrefLocalizedString).data;
} catch (e) { }
return locale;
listManager.setUpdateUrl(this.updateURL);
// XXX Bug 779317 - setKeyUrl has the side effect of fetching a key from the server.
// This shouldn't happen if anti-phishing/anti-malware is disabled.
if (this.phishingEnabled || this.malwareEnabled)
listManager.setKeyUrl(this.keyURL);
listManager.setGethashUrl(this.gethashURL);
},
@ -179,7 +144,7 @@ var SafeBrowsing = {
addMozEntries: function() {
// Add test entries to the DB.
// XXX this should really just be done by DB itself for all moz apps.
// XXX bug 779008 - this could be done by DB itself?
const phishURL = "mozilla.org/firefox/its-a-trap.html";
const malwareURL = "mozilla.org/firefox/its-an-attack.html";

View File

@ -417,9 +417,9 @@ user_pref("camino.warn_when_closing", false); // Camino-only, harmless to others
// Make url-classifier updates so rare that they won't affect tests
user_pref("urlclassifier.updateinterval", 172800);
// Point the url-classifier to the local testing server for fast failures
user_pref("browser.safebrowsing.provider.0.gethashURL", "http://%(server)s/safebrowsing-dummy/gethash");
user_pref("browser.safebrowsing.provider.0.keyURL", "http://%(server)s/safebrowsing-dummy/newkey");
user_pref("browser.safebrowsing.provider.0.updateURL", "http://%(server)s/safebrowsing-dummy/update");
user_pref("browser.safebrowsing.gethashURL", "http://%(server)s/safebrowsing-dummy/gethash");
user_pref("browser.safebrowsing.keyURL", "http://%(server)s/safebrowsing-dummy/newkey");
user_pref("browser.safebrowsing.updateURL", "http://%(server)s/safebrowsing-dummy/update");
// Point update checks to the local testing server for fast failures
user_pref("extensions.update.url", "http://%(server)s/extensions-dummy/updateURL");
user_pref("extensions.update.background.url", "http://%(server)s/extensions-dummy/updateBackgroundURL");

View File

@ -17,15 +17,19 @@ interface nsIFrameMessageListener : nsISupports
* receiveMessage is called with one parameter, which has the following
* properties:
* {
* target: %the target of the message. Either an element owning
* the message manager, or message manager itself if no
* element owns it%
* name: %message name%,
* sync: %true or false%.
* json: %json object or null%,
* json: %structured clone of the sent message data%,
* json: %same as .data, deprecated%,
* objects: %array of handles or null, always null if sync is false%
* }
* @note objects property isn't implemented yet.
*
* if the message is synchronous, possible return value is sent back
* as JSON.
* as JSON (will be changed to use structured clones).
*
* When the listener is called, 'this' value is the target of the message.
*/

View File

@ -128,6 +128,7 @@ CPPSRCS = \
FragmentOrElement.cpp \
Link.cpp \
nsBlobProtocolHandler.cpp \
nsBlobURI.cpp \
nsFrameMessageManager.cpp \
nsInProcessTabChildGlobal.cpp \
ThirdPartyUtil.cpp \

View File

@ -3,19 +3,12 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsBlobProtocolHandler.h"
#include "nsSimpleURI.h"
#include "nsBlobURI.h"
#include "nsDOMError.h"
#include "nsCOMPtr.h"
#include "nsClassHashtable.h"
#include "nsNetUtil.h"
#include "nsIURIWithPrincipal.h"
#include "nsIPrincipal.h"
#include "nsIDOMFile.h"
#include "nsISerializable.h"
#include "nsIClassInfo.h"
#include "nsIObjectInputStream.h"
#include "nsIObjectOutputStream.h"
#include "nsIProgrammingLanguage.h"
// -----------------------------------------------------------------------
// Hash table
@ -89,233 +82,6 @@ GetFileDataInfo(const nsACString& aUri)
return res;
}
// -----------------------------------------------------------------------
// Uri
#define NS_BLOBURI_CID \
{ 0xf5475c51, 0x59a7, 0x4757, \
{ 0xb3, 0xd9, 0xe2, 0x11, 0xa9, 0x41, 0x08, 0x72 } }
static NS_DEFINE_CID(kBLOBURICID, NS_BLOBURI_CID);
class nsBlobURI : public nsSimpleURI,
public nsIURIWithPrincipal
{
public:
nsBlobURI(nsIPrincipal* aPrincipal) :
nsSimpleURI(), mPrincipal(aPrincipal)
{}
virtual ~nsBlobURI() {}
// For use only from deserialization
nsBlobURI() : nsSimpleURI() {}
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIURIWITHPRINCIPAL
NS_DECL_NSISERIALIZABLE
NS_DECL_NSICLASSINFO
// Override CloneInternal() and EqualsInternal()
virtual nsresult CloneInternal(RefHandlingEnum aRefHandlingMode,
nsIURI** aClone);
virtual nsresult EqualsInternal(nsIURI* aOther,
RefHandlingEnum aRefHandlingMode,
bool* aResult);
// Override StartClone to hand back a nsBlobURI
virtual nsSimpleURI* StartClone(RefHandlingEnum /* unused */)
{ return new nsBlobURI(); }
nsCOMPtr<nsIPrincipal> mPrincipal;
};
static NS_DEFINE_CID(kThisSimpleURIImplementationCID,
NS_THIS_SIMPLEURI_IMPLEMENTATION_CID);
NS_IMPL_ADDREF_INHERITED(nsBlobURI, nsSimpleURI)
NS_IMPL_RELEASE_INHERITED(nsBlobURI, nsSimpleURI)
NS_INTERFACE_MAP_BEGIN(nsBlobURI)
NS_INTERFACE_MAP_ENTRY(nsIURIWithPrincipal)
if (aIID.Equals(kBLOBURICID))
foundInterface = static_cast<nsIURI*>(this);
else if (aIID.Equals(kThisSimpleURIImplementationCID)) {
// Need to return explicitly here, because if we just set foundInterface
// to null the NS_INTERFACE_MAP_END_INHERITING will end up calling into
// nsSimplURI::QueryInterface and finding something for this CID.
*aInstancePtr = nullptr;
return NS_NOINTERFACE;
}
else
NS_INTERFACE_MAP_END_INHERITING(nsSimpleURI)
// nsIURIWithPrincipal methods:
NS_IMETHODIMP
nsBlobURI::GetPrincipal(nsIPrincipal** aPrincipal)
{
NS_IF_ADDREF(*aPrincipal = mPrincipal);
return NS_OK;
}
NS_IMETHODIMP
nsBlobURI::GetPrincipalUri(nsIURI** aUri)
{
if (mPrincipal) {
mPrincipal->GetURI(aUri);
}
else {
*aUri = nullptr;
}
return NS_OK;
}
// nsISerializable methods:
NS_IMETHODIMP
nsBlobURI::Read(nsIObjectInputStream* aStream)
{
nsresult rv = nsSimpleURI::Read(aStream);
NS_ENSURE_SUCCESS(rv, rv);
return NS_ReadOptionalObject(aStream, true, getter_AddRefs(mPrincipal));
}
NS_IMETHODIMP
nsBlobURI::Write(nsIObjectOutputStream* aStream)
{
nsresult rv = nsSimpleURI::Write(aStream);
NS_ENSURE_SUCCESS(rv, rv);
return NS_WriteOptionalCompoundObject(aStream, mPrincipal,
NS_GET_IID(nsIPrincipal),
true);
}
// nsIURI methods:
nsresult
nsBlobURI::CloneInternal(nsSimpleURI::RefHandlingEnum aRefHandlingMode,
nsIURI** aClone)
{
nsCOMPtr<nsIURI> simpleClone;
nsresult rv =
nsSimpleURI::CloneInternal(aRefHandlingMode, getter_AddRefs(simpleClone));
NS_ENSURE_SUCCESS(rv, rv);
#ifdef DEBUG
nsRefPtr<nsBlobURI> uriCheck;
rv = simpleClone->QueryInterface(kBLOBURICID, getter_AddRefs(uriCheck));
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv) && uriCheck,
"Unexpected!");
#endif
nsBlobURI* blobURI = static_cast<nsBlobURI*>(simpleClone.get());
blobURI->mPrincipal = mPrincipal;
simpleClone.forget(aClone);
return NS_OK;
}
/* virtual */ nsresult
nsBlobURI::EqualsInternal(nsIURI* aOther,
nsSimpleURI::RefHandlingEnum aRefHandlingMode,
bool* aResult)
{
if (!aOther) {
*aResult = false;
return NS_OK;
}
nsRefPtr<nsBlobURI> otherBlobUri;
aOther->QueryInterface(kBLOBURICID, getter_AddRefs(otherBlobUri));
if (!otherBlobUri) {
*aResult = false;
return NS_OK;
}
// Compare the member data that our base class knows about.
if (!nsSimpleURI::EqualsInternal(otherBlobUri, aRefHandlingMode)) {
*aResult = false;
return NS_OK;
}
// Compare the piece of additional member data that we add to base class.
if (mPrincipal && otherBlobUri->mPrincipal) {
// Both of us have mPrincipals. Compare them.
return mPrincipal->Equals(otherBlobUri->mPrincipal, aResult);
}
// else, at least one of us lacks a principal; only equal if *both* lack it.
*aResult = (!mPrincipal && !otherBlobUri->mPrincipal);
return NS_OK;
}
// nsIClassInfo methods:
NS_IMETHODIMP
nsBlobURI::GetInterfaces(PRUint32 *count, nsIID * **array)
{
*count = 0;
*array = nullptr;
return NS_OK;
}
NS_IMETHODIMP
nsBlobURI::GetHelperForLanguage(PRUint32 language, nsISupports **_retval)
{
*_retval = nullptr;
return NS_OK;
}
NS_IMETHODIMP
nsBlobURI::GetContractID(char * *aContractID)
{
// Make sure to modify any subclasses as needed if this ever
// changes.
*aContractID = nullptr;
return NS_OK;
}
NS_IMETHODIMP
nsBlobURI::GetClassDescription(char * *aClassDescription)
{
*aClassDescription = nullptr;
return NS_OK;
}
NS_IMETHODIMP
nsBlobURI::GetClassID(nsCID * *aClassID)
{
// Make sure to modify any subclasses as needed if this ever
// changes to not call the virtual GetClassIDNoAlloc.
*aClassID = (nsCID*) nsMemory::Alloc(sizeof(nsCID));
NS_ENSURE_TRUE(*aClassID, NS_ERROR_OUT_OF_MEMORY);
return GetClassIDNoAlloc(*aClassID);
}
NS_IMETHODIMP
nsBlobURI::GetImplementationLanguage(PRUint32 *aImplementationLanguage)
{
*aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
return NS_OK;
}
NS_IMETHODIMP
nsBlobURI::GetFlags(PRUint32 *aFlags)
{
*aFlags = nsIClassInfo::MAIN_THREAD_ONLY;
return NS_OK;
}
NS_IMETHODIMP
nsBlobURI::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
{
*aClassIDNoAlloc = kBLOBURICID;
return NS_OK;
}
// -----------------------------------------------------------------------
// Protocol handler

View File

@ -0,0 +1,199 @@
/* 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 "nsBlobURI.h"
#include "nsAutoPtr.h"
#include "nsIObjectInputStream.h"
#include "nsIObjectOutputStream.h"
#include "nsIProgrammingLanguage.h"
static NS_DEFINE_CID(kBLOBURICID, NS_BLOBURI_CID);
static NS_DEFINE_CID(kThisSimpleURIImplementationCID,
NS_THIS_SIMPLEURI_IMPLEMENTATION_CID);
NS_IMPL_ADDREF_INHERITED(nsBlobURI, nsSimpleURI)
NS_IMPL_RELEASE_INHERITED(nsBlobURI, nsSimpleURI)
NS_INTERFACE_MAP_BEGIN(nsBlobURI)
NS_INTERFACE_MAP_ENTRY(nsIURIWithPrincipal)
if (aIID.Equals(kBLOBURICID))
foundInterface = static_cast<nsIURI*>(this);
else if (aIID.Equals(kThisSimpleURIImplementationCID)) {
// Need to return explicitly here, because if we just set foundInterface
// to null the NS_INTERFACE_MAP_END_INHERITING will end up calling into
// nsSimplURI::QueryInterface and finding something for this CID.
*aInstancePtr = nullptr;
return NS_NOINTERFACE;
}
else
NS_INTERFACE_MAP_END_INHERITING(nsSimpleURI)
// nsIURIWithPrincipal methods:
NS_IMETHODIMP
nsBlobURI::GetPrincipal(nsIPrincipal** aPrincipal)
{
NS_IF_ADDREF(*aPrincipal = mPrincipal);
return NS_OK;
}
NS_IMETHODIMP
nsBlobURI::GetPrincipalUri(nsIURI** aUri)
{
if (mPrincipal) {
mPrincipal->GetURI(aUri);
}
else {
*aUri = nullptr;
}
return NS_OK;
}
// nsISerializable methods:
NS_IMETHODIMP
nsBlobURI::Read(nsIObjectInputStream* aStream)
{
nsresult rv = nsSimpleURI::Read(aStream);
NS_ENSURE_SUCCESS(rv, rv);
return NS_ReadOptionalObject(aStream, true, getter_AddRefs(mPrincipal));
}
NS_IMETHODIMP
nsBlobURI::Write(nsIObjectOutputStream* aStream)
{
nsresult rv = nsSimpleURI::Write(aStream);
NS_ENSURE_SUCCESS(rv, rv);
return NS_WriteOptionalCompoundObject(aStream, mPrincipal,
NS_GET_IID(nsIPrincipal),
true);
}
// nsIURI methods:
nsresult
nsBlobURI::CloneInternal(nsSimpleURI::RefHandlingEnum aRefHandlingMode,
nsIURI** aClone)
{
nsCOMPtr<nsIURI> simpleClone;
nsresult rv =
nsSimpleURI::CloneInternal(aRefHandlingMode, getter_AddRefs(simpleClone));
NS_ENSURE_SUCCESS(rv, rv);
#ifdef DEBUG
nsRefPtr<nsBlobURI> uriCheck;
rv = simpleClone->QueryInterface(kBLOBURICID, getter_AddRefs(uriCheck));
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv) && uriCheck,
"Unexpected!");
#endif
nsBlobURI* blobURI = static_cast<nsBlobURI*>(simpleClone.get());
blobURI->mPrincipal = mPrincipal;
simpleClone.forget(aClone);
return NS_OK;
}
/* virtual */ nsresult
nsBlobURI::EqualsInternal(nsIURI* aOther,
nsSimpleURI::RefHandlingEnum aRefHandlingMode,
bool* aResult)
{
if (!aOther) {
*aResult = false;
return NS_OK;
}
nsRefPtr<nsBlobURI> otherBlobUri;
aOther->QueryInterface(kBLOBURICID, getter_AddRefs(otherBlobUri));
if (!otherBlobUri) {
*aResult = false;
return NS_OK;
}
// Compare the member data that our base class knows about.
if (!nsSimpleURI::EqualsInternal(otherBlobUri, aRefHandlingMode)) {
*aResult = false;
return NS_OK;
}
// Compare the piece of additional member data that we add to base class.
if (mPrincipal && otherBlobUri->mPrincipal) {
// Both of us have mPrincipals. Compare them.
return mPrincipal->Equals(otherBlobUri->mPrincipal, aResult);
}
// else, at least one of us lacks a principal; only equal if *both* lack it.
*aResult = (!mPrincipal && !otherBlobUri->mPrincipal);
return NS_OK;
}
// nsIClassInfo methods:
NS_IMETHODIMP
nsBlobURI::GetInterfaces(PRUint32 *count, nsIID * **array)
{
*count = 0;
*array = nullptr;
return NS_OK;
}
NS_IMETHODIMP
nsBlobURI::GetHelperForLanguage(PRUint32 language, nsISupports **_retval)
{
*_retval = nullptr;
return NS_OK;
}
NS_IMETHODIMP
nsBlobURI::GetContractID(char * *aContractID)
{
// Make sure to modify any subclasses as needed if this ever
// changes.
*aContractID = nullptr;
return NS_OK;
}
NS_IMETHODIMP
nsBlobURI::GetClassDescription(char * *aClassDescription)
{
*aClassDescription = nullptr;
return NS_OK;
}
NS_IMETHODIMP
nsBlobURI::GetClassID(nsCID * *aClassID)
{
// Make sure to modify any subclasses as needed if this ever
// changes to not call the virtual GetClassIDNoAlloc.
*aClassID = (nsCID*) nsMemory::Alloc(sizeof(nsCID));
NS_ENSURE_TRUE(*aClassID, NS_ERROR_OUT_OF_MEMORY);
return GetClassIDNoAlloc(*aClassID);
}
NS_IMETHODIMP
nsBlobURI::GetImplementationLanguage(PRUint32 *aImplementationLanguage)
{
*aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
return NS_OK;
}
NS_IMETHODIMP
nsBlobURI::GetFlags(PRUint32 *aFlags)
{
*aFlags = nsIClassInfo::MAIN_THREAD_ONLY;
return NS_OK;
}
NS_IMETHODIMP
nsBlobURI::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
{
*aClassIDNoAlloc = kBLOBURICID;
return NS_OK;
}

View File

@ -0,0 +1,50 @@
/* 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 nsBlobURI_h
#define nsBlobURI_h
#include "nsCOMPtr.h"
#include "nsIClassInfo.h"
#include "nsIPrincipal.h"
#include "nsISerializable.h"
#include "nsIURIWithPrincipal.h"
#include "nsSimpleURI.h"
class nsBlobURI : public nsSimpleURI,
public nsIURIWithPrincipal
{
public:
nsBlobURI(nsIPrincipal* aPrincipal) :
nsSimpleURI(), mPrincipal(aPrincipal)
{}
virtual ~nsBlobURI() {}
// For use only from deserialization
nsBlobURI() : nsSimpleURI() {}
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIURIWITHPRINCIPAL
NS_DECL_NSISERIALIZABLE
NS_DECL_NSICLASSINFO
// Override CloneInternal() and EqualsInternal()
virtual nsresult CloneInternal(RefHandlingEnum aRefHandlingMode,
nsIURI** aClone);
virtual nsresult EqualsInternal(nsIURI* aOther,
RefHandlingEnum aRefHandlingMode,
bool* aResult);
// Override StartClone to hand back a nsBlobURI
virtual nsSimpleURI* StartClone(RefHandlingEnum /* unused */)
{ return new nsBlobURI(); }
nsCOMPtr<nsIPrincipal> mPrincipal;
};
#define NS_BLOBURI_CID \
{ 0xf5475c51, 0x59a7, 0x4757, \
{ 0xb3, 0xd9, 0xe2, 0x11, 0xa9, 0x41, 0x08, 0x72 } }
#endif /* nsBlobURI_h */

View File

@ -22,6 +22,7 @@
#include "nsIContentViewer.h"
#include "nsIDocument.h"
#include "nsIDOMDocument.h"
#include "nsIDOMFile.h"
#include "nsPIDOMWindow.h"
#include "nsIWebNavigation.h"
#include "nsIWebProgress.h"
@ -83,6 +84,7 @@
#include "nsIAppsService.h"
#include "jsapi.h"
#include "mozilla/dom/StructuredCloneUtils.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -2156,8 +2158,15 @@ class nsAsyncMessageToChild : public nsRunnable
{
public:
nsAsyncMessageToChild(nsFrameLoader* aFrameLoader,
const nsAString& aMessage, const nsAString& aJSON)
: mFrameLoader(aFrameLoader), mMessage(aMessage), mJSON(aJSON) {}
const nsAString& aMessage,
const StructuredCloneData& aData)
: mFrameLoader(aFrameLoader), mMessage(aMessage)
{
if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) {
NS_RUNTIMEABORT("OOM");
}
mClosure = aData.mClosure;
}
NS_IMETHOD Run()
{
@ -2165,29 +2174,62 @@ public:
static_cast<nsInProcessTabChildGlobal*>(mFrameLoader->mChildMessageManager.get());
if (tabChild && tabChild->GetInnerManager()) {
nsFrameScriptCx cx(static_cast<nsIDOMEventTarget*>(tabChild), tabChild);
StructuredCloneData data;
data.mData = mData.data();
data.mDataLength = mData.nbytes();
data.mClosure = mClosure;
nsRefPtr<nsFrameMessageManager> mm = tabChild->GetInnerManager();
mm->ReceiveMessage(static_cast<nsIDOMEventTarget*>(tabChild), mMessage,
false, mJSON, nullptr, nullptr);
false, &data, nullptr, nullptr, nullptr);
}
return NS_OK;
}
nsRefPtr<nsFrameLoader> mFrameLoader;
nsString mMessage;
nsString mJSON;
JSAutoStructuredCloneBuffer mData;
StructuredCloneClosure mClosure;
};
bool SendAsyncMessageToChild(void* aCallbackData,
const nsAString& aMessage,
const nsAString& aJSON)
const StructuredCloneData& aData)
{
mozilla::dom::PBrowserParent* tabParent =
PBrowserParent* tabParent =
static_cast<nsFrameLoader*>(aCallbackData)->GetRemoteBrowser();
if (tabParent) {
return tabParent->SendAsyncMessage(nsString(aMessage), nsString(aJSON));
ClonedMessageData data;
SerializedStructuredCloneBuffer& buffer = data.data();
buffer.data = aData.mData;
buffer.dataLength = aData.mDataLength;
const nsTArray<nsCOMPtr<nsIDOMBlob> >& blobs = aData.mClosure.mBlobs;
if (!blobs.IsEmpty()) {
InfallibleTArray<PBlobParent*>& blobParents = data.blobsParent();
PRUint32 length = blobs.Length();
blobParents.SetCapacity(length);
ContentParent* cp = static_cast<ContentParent*>(tabParent->Manager());
for (PRUint32 i = 0; i < length; ++i) {
BlobParent* blobParent = cp->GetOrCreateActorForBlob(blobs[i]);
if (!blobParent) {
return false;
}
blobParents.AppendElement(blobParent);
}
}
return tabParent->SendAsyncMessage(nsString(aMessage), data);
}
nsRefPtr<nsIRunnable> ev =
new nsAsyncMessageToChild(static_cast<nsFrameLoader*>(aCallbackData),
aMessage, aJSON);
aMessage, aData);
NS_DispatchToCurrentThread(ev);
return true;
}

View File

@ -3,9 +3,12 @@
* 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 "base/basictypes.h"
#include "nsFrameMessageManager.h"
#include "ContentChild.h"
#include "ContentParent.h"
#include "nsFrameMessageManager.h"
#include "nsContentUtils.h"
#include "nsIXPConnect.h"
#include "jsapi.h"
@ -20,14 +23,17 @@
#include "nsIProtocolHandler.h"
#include "nsIScriptSecurityManager.h"
#include "nsIJSRuntimeService.h"
#include "nsIDOMFile.h"
#include "xpcpublic.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/StructuredCloneUtils.h"
#ifdef ANDROID
#include <android/log.h>
#endif
using namespace mozilla;
using namespace mozilla::dom;
static bool
IsChromeProcess()
@ -170,15 +176,32 @@ JSONCreator(const jschar* aBuf, uint32_t aLen, void* aData)
return true;
}
void
nsFrameMessageManager::GetParamsForMessage(const jsval& aObject,
JSContext* aCx,
nsAString& aJSON)
static bool
GetParamsForMessage(JSContext* aCx,
const jsval& aObject,
JSAutoStructuredCloneBuffer& aBuffer,
StructuredCloneClosure& aClosure)
{
aJSON.Truncate();
if (WriteStructuredClone(aCx, aObject, aBuffer, aClosure)) {
return true;
}
JS_ClearPendingException(aCx);
// Not clonable, try JSON
//XXX This is ugly but currently structured cloning doesn't handle
// properly cases when interface is implemented in JS and used
// as a dictionary.
nsAutoString json;
JSAutoRequest ar(aCx);
jsval v = aObject;
JS_Stringify(aCx, &v, nullptr, JSVAL_NULL, JSONCreator, &aJSON);
NS_ENSURE_TRUE(JS_Stringify(aCx, &v, nullptr, JSVAL_NULL, JSONCreator, &json), false);
NS_ENSURE_TRUE(!json.IsEmpty(), false);
jsval val = JSVAL_NULL;
NS_ENSURE_TRUE(JS_ParseJSON(aCx, static_cast<const jschar*>(PromiseFlatString(json).get()),
json.Length(), &val), false);
return WriteStructuredClone(aCx, val, aBuffer, aClosure);
}
NS_IMETHODIMP
@ -194,12 +217,17 @@ nsFrameMessageManager::SendSyncMessage(const nsAString& aMessageName,
*aRetval = JSVAL_VOID;
if (mSyncCallback) {
NS_ENSURE_TRUE(mCallbackData, NS_ERROR_NOT_INITIALIZED);
nsString json;
if (aArgc >= 2) {
GetParamsForMessage(aObject, aCx, json);
StructuredCloneData data;
JSAutoStructuredCloneBuffer buffer;
if (aArgc >= 2 &&
!GetParamsForMessage(aCx, aObject, buffer, data.mClosure)) {
return NS_ERROR_DOM_DATA_CLONE_ERR;
}
data.mData = buffer.data();
data.mDataLength = buffer.nbytes();
InfallibleTArray<nsString> retval;
if (mSyncCallback(mCallbackData, aMessageName, json, &retval)) {
if (mSyncCallback(mCallbackData, aMessageName, data, &retval)) {
JSAutoRequest ar(aCx);
PRUint32 len = retval.Length();
JSObject* dataArray = JS_NewArrayObject(aCx, len, NULL);
@ -226,16 +254,16 @@ nsFrameMessageManager::SendSyncMessage(const nsAString& aMessageName,
nsresult
nsFrameMessageManager::SendAsyncMessageInternal(const nsAString& aMessage,
const nsAString& aJSON)
const StructuredCloneData& aData)
{
if (mAsyncCallback) {
NS_ENSURE_TRUE(mCallbackData, NS_ERROR_NOT_INITIALIZED);
mAsyncCallback(mCallbackData, aMessage, aJSON);
mAsyncCallback(mCallbackData, aMessage, aData);
}
PRInt32 len = mChildManagers.Count();
for (PRInt32 i = 0; i < len; ++i) {
static_cast<nsFrameMessageManager*>(mChildManagers[i])->
SendAsyncMessageInternal(aMessage, aJSON);
SendAsyncMessageInternal(aMessage, aData);
}
return NS_OK;
}
@ -246,11 +274,18 @@ nsFrameMessageManager::SendAsyncMessage(const nsAString& aMessageName,
JSContext* aCx,
PRUint8 aArgc)
{
nsString json;
if (aArgc >= 2) {
GetParamsForMessage(aObject, aCx, json);
StructuredCloneData data;
JSAutoStructuredCloneBuffer buffer;
if (aArgc >= 2 &&
!GetParamsForMessage(aCx, aObject, buffer, data.mClosure)) {
return NS_ERROR_DOM_DATA_CLONE_ERR;
}
return SendAsyncMessageInternal(aMessageName, json);
data.mData = buffer.data();
data.mDataLength = buffer.nbytes();
return SendAsyncMessageInternal(aMessageName, data);
}
NS_IMETHODIMP
@ -342,7 +377,8 @@ public:
nsresult
nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
const nsAString& aMessage,
bool aSync, const nsAString& aJSON,
bool aSync,
const StructuredCloneData* aCloneData,
JSObject* aObjectsArray,
InfallibleTArray<nsString>* aJSONRetVal,
JSContext* aContext)
@ -402,11 +438,10 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
return NS_ERROR_UNEXPECTED;
jsval json = JSVAL_NULL;
if (!aJSON.IsEmpty()) {
if (!JS_ParseJSON(ctx, static_cast<const jschar*>(PromiseFlatString(aJSON).get()),
aJSON.Length(), &json)) {
json = JSVAL_NULL;
}
if (aCloneData && aCloneData->mDataLength &&
!ReadStructuredClone(ctx, *aCloneData, &json)) {
JS_ClearPendingException(ctx);
return NS_OK;
}
JSString* jsMessage =
JS_NewUCStringCopyN(ctx,
@ -418,7 +453,8 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
STRING_TO_JSVAL(jsMessage), NULL, NULL, JSPROP_ENUMERATE);
JS_DefineProperty(ctx, param, "sync",
BOOLEAN_TO_JSVAL(aSync), NULL, NULL, JSPROP_ENUMERATE);
JS_DefineProperty(ctx, param, "json", json, NULL, NULL, JSPROP_ENUMERATE);
JS_DefineProperty(ctx, param, "json", json, NULL, NULL, JSPROP_ENUMERATE); // deprecated
JS_DefineProperty(ctx, param, "data", json, NULL, NULL, JSPROP_ENUMERATE);
JS_DefineProperty(ctx, param, "objects", objectsv.jsval_value(), NULL, NULL, JSPROP_ENUMERATE);
jsval thisValue = JSVAL_VOID;
@ -479,7 +515,8 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
}
nsRefPtr<nsFrameMessageManager> kungfuDeathGrip = mParentManager;
return mParentManager ? mParentManager->ReceiveMessage(aTarget, aMessage,
aSync, aJSON, aObjectsArray,
aSync, aCloneData,
aObjectsArray,
aJSONRetVal, mContext) : NS_OK;
}
@ -888,13 +925,31 @@ nsTArray<nsCOMPtr<nsIRunnable> >* nsFrameMessageManager::sPendingSameProcessAsyn
bool SendAsyncMessageToChildProcess(void* aCallbackData,
const nsAString& aMessage,
const nsAString& aJSON)
const StructuredCloneData& aData)
{
mozilla::dom::ContentParent* cp =
static_cast<mozilla::dom::ContentParent*>(aCallbackData);
NS_WARN_IF_FALSE(cp, "No child process!");
if (cp) {
return cp->SendAsyncMessage(nsString(aMessage), nsString(aJSON));
ClonedMessageData data;
SerializedStructuredCloneBuffer& buffer = data.data();
buffer.data = aData.mData;
buffer.dataLength = aData.mDataLength;
const nsTArray<nsCOMPtr<nsIDOMBlob> >& blobs = aData.mClosure.mBlobs;
if (!blobs.IsEmpty()) {
InfallibleTArray<PBlobParent*>& blobParents = data.blobsParent();
PRUint32 length = blobs.Length();
blobParents.SetCapacity(length);
for (PRUint32 i = 0; i < length; ++i) {
BlobParent* blobParent = cp->GetOrCreateActorForBlob(blobs[i]);
if (!blobParent) {
return false;
}
blobParents.AppendElement(blobParent);
}
}
return cp->SendAsyncMessage(nsString(aMessage), data);
}
return true;
}
@ -902,49 +957,79 @@ bool SendAsyncMessageToChildProcess(void* aCallbackData,
class nsAsyncMessageToSameProcessChild : public nsRunnable
{
public:
nsAsyncMessageToSameProcessChild(const nsAString& aMessage, const nsAString& aJSON)
: mMessage(aMessage), mJSON(aJSON) {}
nsAsyncMessageToSameProcessChild(const nsAString& aMessage,
const StructuredCloneData& aData)
: mMessage(aMessage)
{
if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) {
NS_RUNTIMEABORT("OOM");
}
mClosure = aData.mClosure;
}
NS_IMETHOD Run()
{
if (nsFrameMessageManager::sChildProcessManager) {
StructuredCloneData data;
data.mData = mData.data();
data.mDataLength = mData.nbytes();
data.mClosure = mClosure;
nsRefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sChildProcessManager;
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), mMessage,
false, mJSON, nullptr, nullptr);
false, &data, nullptr, nullptr, nullptr);
}
return NS_OK;
}
nsString mMessage;
nsString mJSON;
JSAutoStructuredCloneBuffer mData;
StructuredCloneClosure mClosure;
};
bool SendAsyncMessageToSameProcessChild(void* aCallbackData,
const nsAString& aMessage,
const nsAString& aJSON)
const StructuredCloneData& aData)
{
nsRefPtr<nsIRunnable> ev =
new nsAsyncMessageToSameProcessChild(aMessage, aJSON);
new nsAsyncMessageToSameProcessChild(aMessage, aData);
NS_DispatchToCurrentThread(ev);
return true;
}
bool SendSyncMessageToParentProcess(void* aCallbackData,
const nsAString& aMessage,
const nsAString& aJSON,
const StructuredCloneData& aData,
InfallibleTArray<nsString>* aJSONRetVal)
{
mozilla::dom::ContentChild* cc =
mozilla::dom::ContentChild::GetSingleton();
if (cc) {
ClonedMessageData data;
SerializedStructuredCloneBuffer& buffer = data.data();
buffer.data = aData.mData;
buffer.dataLength = aData.mDataLength;
const nsTArray<nsCOMPtr<nsIDOMBlob> >& blobs = aData.mClosure.mBlobs;
if (!blobs.IsEmpty()) {
InfallibleTArray<PBlobChild*>& blobChildList = data.blobsChild();
PRUint32 length = blobs.Length();
blobChildList.SetCapacity(length);
for (PRUint32 i = 0; i < length; ++i) {
BlobChild* blobChild = cc->GetOrCreateActorForBlob(blobs[i]);
if (!blobChild) {
return false;
}
blobChildList.AppendElement(blobChild);
}
}
return
cc->SendSyncMessage(nsString(aMessage), nsString(aJSON), aJSONRetVal);
cc->SendSyncMessage(nsString(aMessage), data, aJSONRetVal);
}
return true;
}
bool SendSyncMessageToSameProcessParent(void* aCallbackData,
const nsAString& aMessage,
const nsAString& aJSON,
const StructuredCloneData& aData,
InfallibleTArray<nsString>* aJSONRetVal)
{
nsTArray<nsCOMPtr<nsIRunnable> > asyncMessages;
@ -959,19 +1044,36 @@ bool SendSyncMessageToSameProcessParent(void* aCallbackData,
if (nsFrameMessageManager::sSameProcessParentManager) {
nsRefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sSameProcessParentManager;
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), aMessage,
true, aJSON, nullptr, aJSONRetVal);
true, &aData, nullptr, aJSONRetVal);
}
return true;
}
bool SendAsyncMessageToParentProcess(void* aCallbackData,
const nsAString& aMessage,
const nsAString& aJSON)
const StructuredCloneData& aData)
{
mozilla::dom::ContentChild* cc =
mozilla::dom::ContentChild::GetSingleton();
if (cc) {
return cc->SendAsyncMessage(nsString(aMessage), nsString(aJSON));
ClonedMessageData data;
SerializedStructuredCloneBuffer& buffer = data.data();
buffer.data = aData.mData;
buffer.dataLength = aData.mDataLength;
const nsTArray<nsCOMPtr<nsIDOMBlob> >& blobs = aData.mClosure.mBlobs;
if (!blobs.IsEmpty()) {
InfallibleTArray<PBlobChild*>& blobChildList = data.blobsChild();
PRUint32 length = blobs.Length();
blobChildList.SetCapacity(length);
for (PRUint32 i = 0; i < length; ++i) {
BlobChild* blobChild = cc->GetOrCreateActorForBlob(blobs[i]);
if (!blobChild) {
return false;
}
blobChildList.AppendElement(blobChild);
}
}
return cc->SendAsyncMessage(nsString(aMessage), data);
}
return true;
}
@ -979,8 +1081,15 @@ bool SendAsyncMessageToParentProcess(void* aCallbackData,
class nsAsyncMessageToSameProcessParent : public nsRunnable
{
public:
nsAsyncMessageToSameProcessParent(const nsAString& aMessage, const nsAString& aJSON)
: mMessage(aMessage), mJSON(aJSON) {}
nsAsyncMessageToSameProcessParent(const nsAString& aMessage,
const StructuredCloneData& aData)
: mMessage(aMessage)
{
if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) {
NS_RUNTIMEABORT("OOM");
}
mClosure = aData.mClosure;
}
NS_IMETHOD Run()
{
@ -988,25 +1097,32 @@ public:
nsFrameMessageManager::sPendingSameProcessAsyncMessages->RemoveElement(this);
}
if (nsFrameMessageManager::sSameProcessParentManager) {
nsRefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sSameProcessParentManager;
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), mMessage, false,
mJSON, nullptr, nullptr);
}
return NS_OK;
StructuredCloneData data;
data.mData = mData.data();
data.mDataLength = mData.nbytes();
data.mClosure = mClosure;
nsRefPtr<nsFrameMessageManager> ppm =
nsFrameMessageManager::sSameProcessParentManager;
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
mMessage, false, &data, nullptr, nullptr, nullptr);
}
return NS_OK;
}
nsString mMessage;
nsString mJSON;
JSAutoStructuredCloneBuffer mData;
StructuredCloneClosure mClosure;
};
bool SendAsyncMessageToSameProcessParent(void* aCallbackData,
const nsAString& aMessage,
const nsAString& aJSON)
const nsAString& aMessage,
const StructuredCloneData& aData)
{
if (!nsFrameMessageManager::sPendingSameProcessAsyncMessages) {
nsFrameMessageManager::sPendingSameProcessAsyncMessages = new nsTArray<nsCOMPtr<nsIRunnable> >;
}
nsCOMPtr<nsIRunnable> ev =
new nsAsyncMessageToSameProcessParent(aMessage, aJSON);
new nsAsyncMessageToSameProcessParent(aMessage, aData);
nsFrameMessageManager::sPendingSameProcessAsyncMessages->AppendElement(ev);
NS_DispatchToCurrentThread(ev);
return true;
@ -1089,4 +1205,4 @@ nsFrameMessageManager::MarkForCC()
xpc_TryUnmarkWrappedGrayObject(mListeners[i].mListener);
}
return true;
}
}

View File

@ -25,6 +25,7 @@
namespace mozilla {
namespace dom {
class ContentParent;
struct StructuredCloneData;
}
}
@ -41,15 +42,16 @@ struct nsMessageListenerInfo
typedef bool (*nsLoadScriptCallback)(void* aCallbackData, const nsAString& aURL);
typedef bool (*nsSyncMessageCallback)(void* aCallbackData,
const nsAString& aMessage,
const nsAString& aJSON,
const mozilla::dom::StructuredCloneData& aData,
InfallibleTArray<nsString>* aJSONRetVal);
typedef bool (*nsAsyncMessageCallback)(void* aCallbackData,
const nsAString& aMessage,
const nsAString& aJSON);
const mozilla::dom::StructuredCloneData& aData);
class nsFrameMessageManager MOZ_FINAL : public nsIContentFrameMessageManager,
public nsIChromeFrameMessageManager
{
typedef mozilla::dom::StructuredCloneData StructuredCloneData;
public:
nsFrameMessageManager(bool aChrome,
nsSyncMessageCallback aSyncCallback,
@ -63,7 +65,8 @@ public:
: mChrome(aChrome), mGlobal(aGlobal), mIsProcessManager(aProcessManager),
mHandlingMessage(false), mDisconnected(false), mParentManager(aParentManager),
mSyncCallback(aSyncCallback), mAsyncCallback(aAsyncCallback),
mLoadScriptCallback(aLoadScriptCallback), mCallbackData(aCallbackData),
mLoadScriptCallback(aLoadScriptCallback),
mCallbackData(aCallbackData),
mContext(aContext)
{
NS_ASSERTION(mContext || (aChrome && !aParentManager) || aProcessManager,
@ -112,10 +115,11 @@ public:
NewProcessMessageManager(mozilla::dom::ContentParent* aProcess);
nsresult ReceiveMessage(nsISupports* aTarget, const nsAString& aMessage,
bool aSync, const nsAString& aJSON,
bool aSync, const StructuredCloneData* aCloneData,
JSObject* aObjectsArray,
InfallibleTArray<nsString>* aJSONRetVal,
JSContext* aContext = nullptr);
void AddChildManager(nsFrameMessageManager* aManager,
bool aLoadScripts = true);
void RemoveChildManager(nsFrameMessageManager* aManager)
@ -126,11 +130,8 @@ public:
void Disconnect(bool aRemoveFromParent = true);
void SetCallbackData(void* aData, bool aLoadScripts = true);
void* GetCallbackData() { return mCallbackData; }
void GetParamsForMessage(const jsval& aObject,
JSContext* aCx,
nsAString& aJSON);
nsresult SendAsyncMessageInternal(const nsAString& aMessage,
const nsAString& aJSON);
const StructuredCloneData& aData);
JSContext* GetJSContext() { return mContext; }
void SetJSContext(JSContext* aCx) { mContext = aCx; }
void RemoveFromParent();
@ -257,4 +258,4 @@ class nsScriptCacheCleaner MOZ_FINAL : public nsIObserver
}
};
#endif
#endif

View File

@ -20,10 +20,14 @@
#include "xpcpublic.h"
#include "nsIMozBrowserFrame.h"
#include "nsDOMClassInfoID.h"
#include "mozilla/dom/StructuredCloneUtils.h"
using mozilla::dom::StructuredCloneData;
using mozilla::dom::StructuredCloneClosure;
bool SendSyncMessageToParent(void* aCallbackData,
const nsAString& aMessage,
const nsAString& aJSON,
const StructuredCloneData& aData,
InfallibleTArray<nsString>* aJSONRetVal)
{
nsInProcessTabChildGlobal* tabChild =
@ -38,7 +42,7 @@ bool SendSyncMessageToParent(void* aCallbackData,
}
if (tabChild->mChromeMessageManager) {
nsRefPtr<nsFrameMessageManager> mm = tabChild->mChromeMessageManager;
mm->ReceiveMessage(owner, aMessage, true, aJSON, nullptr, aJSONRetVal);
mm->ReceiveMessage(owner, aMessage, true, &aData, nullptr, aJSONRetVal);
}
return true;
}
@ -47,32 +51,45 @@ class nsAsyncMessageToParent : public nsRunnable
{
public:
nsAsyncMessageToParent(nsInProcessTabChildGlobal* aTabChild,
const nsAString& aMessage, const nsAString& aJSON)
: mTabChild(aTabChild), mMessage(aMessage), mJSON(aJSON) {}
const nsAString& aMessage,
const StructuredCloneData& aData)
: mTabChild(aTabChild), mMessage(aMessage)
{
if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) {
NS_RUNTIMEABORT("OOM");
}
mClosure = aData.mClosure;
}
NS_IMETHOD Run()
{
mTabChild->mASyncMessages.RemoveElement(this);
if (mTabChild->mChromeMessageManager) {
StructuredCloneData data;
data.mData = mData.data();
data.mDataLength = mData.nbytes();
data.mClosure = mClosure;
nsRefPtr<nsFrameMessageManager> mm = mTabChild->mChromeMessageManager;
mm->ReceiveMessage(mTabChild->mOwner, mMessage, false,
mJSON, nullptr, nullptr);
mm->ReceiveMessage(mTabChild->mOwner, mMessage, false, &data,
nullptr, nullptr, nullptr);
}
return NS_OK;
}
nsRefPtr<nsInProcessTabChildGlobal> mTabChild;
nsString mMessage;
nsString mJSON;
JSAutoStructuredCloneBuffer mData;
StructuredCloneClosure mClosure;
};
bool SendAsyncMessageToParent(void* aCallbackData,
const nsAString& aMessage,
const nsAString& aJSON)
const StructuredCloneData& aData)
{
nsInProcessTabChildGlobal* tabChild =
static_cast<nsInProcessTabChildGlobal*>(aCallbackData);
nsCOMPtr<nsIRunnable> ev =
new nsAsyncMessageToParent(tabChild, aMessage, aJSON);
new nsAsyncMessageToParent(tabChild, aMessage, aData);
tabChild->mASyncMessages.AppendElement(ev);
NS_DispatchToCurrentThread(ev);
return true;

View File

@ -552,6 +552,7 @@ MOCHITEST_FILES_B = \
file_XHR_anon.sjs \
test_XHR_system.html \
test_XHR_parameters.html \
test_ipc_messagemanager_blob.html \
$(NULL)
MOCHITEST_CHROME_FILES = \

View File

@ -0,0 +1,111 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for OOP Blobs in MessageManager</title>
<script type="application/javascript"
src="/tests/SimpleTest/SimpleTest.js">
</script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="application/javascript;version=1.7">
"use strict";
SimpleTest.waitForExplicitFinish();
const childFrameURL =
"data:text/html,<!DOCTYPE HTML><html><body></body></html>";
function childFrameScript() {
"use strict";
addMessageListener("test:ipcClonedMessage", function(message) {
if (!(message.json instanceof Components.interfaces.nsIDOMBlob)) {
sendAsyncMessage(message.name, message.json);
return;
}
let reader =
Components.classes["@mozilla.org/files/filereader;1"]
.createInstance(Components.interfaces.nsIDOMFileReader);
reader.addEventListener("load", function() {
let response = reader.result == "this is a great success!" ?
message.json :
"error";
sendAsyncMessage(message.name, response);
});
reader.readAsText(message.json);
});
}
function runTests() {
ok("Browser prefs set.");
let iframe = document.createElement("iframe");
iframe.mozbrowser = true;
iframe.id = "iframe";
iframe.src = childFrameURL;
iframe.addEventListener("mozbrowserloadend", function() {
ok(true, "Got iframe load event.");
const messages = [
"hi!",
"",
2,
-.04,
3432987324987239872948732982,
true,
false,
null,
0,
new Blob(["this ", "is ", "a ", "great ", "success!"],
{"type" : "text\/plain"}),
];
let receivedMessageIndex = 0;
let mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
mm.addMessageListener("test:ipcClonedMessage", function(message) {
is(message.json, messages[receivedMessageIndex++],
"Got correct round-tripped response");
if (receivedMessageIndex == messages.length) {
SimpleTest.finish();
}
});
mm.loadFrameScript("data:,(" + childFrameScript.toString() + ")();",
false);
for each (let message in messages) {
mm.sendAsyncMessage("test:ipcClonedMessage", message);
}
});
document.body.appendChild(iframe);
}
addEventListener("load", function() {
info("Got load event.");
let whitelist;
try {
whitelist =
SpecialPowers.getCharPref("dom.mozBrowserFramesWhitelist") + ", ";
} catch (e) {
whitelist = "";
}
whitelist += window.location.protocol + "//" + window.location.host;
SpecialPowers.pushPrefEnv({
"set": [
["dom.ipc.browser_frames.oop_by_default", true],
["dom.mozBrowserFramesEnabled", true],
["dom.mozBrowserFramesWhitelist", whitelist],
["browser.pageThumbs.enabled", false]
]
}, runTests);
});
</script>
</body>
</html>

View File

@ -74,12 +74,13 @@ NS_NewCanvasRenderingContextWebGL(nsIDOMWebGLRenderingContext** aResult)
}
WebGLContextOptions::WebGLContextOptions()
: depth(true), stencil(false),
: alpha(true), depth(true), stencil(false),
premultipliedAlpha(true), antialias(true),
preserveDrawingBuffer(false)
{
// Set default alpha state based on preference.
alpha = Preferences::GetBool("webgl.default-no-alpha", false) ? 0 : 1;
if (Preferences::GetBool("webgl.default-no-alpha", false))
alpha = false;
}
WebGLContext::WebGLContext()

View File

@ -289,21 +289,21 @@ public:
#ifdef MOZ_WAVE
static bool IsWaveEnabled();
static bool IsWaveType(const nsACString& aType);
static const char gWaveTypes[4][16];
static const char gWaveTypes[4][15];
static char const *const gWaveCodecs[2];
#endif
#ifdef MOZ_WEBM
static bool IsWebMEnabled();
static bool IsWebMType(const nsACString& aType);
static const char gWebMTypes[2][17];
static const char gWebMTypes[2][11];
static char const *const gWebMCodecs[4];
#endif
#ifdef MOZ_GSTREAMER
static bool IsH264Enabled();
static bool IsH264Type(const nsACString& aType);
static const char gH264Types[3][17];
static const char gH264Types[3][16];
static char const *const gH264Codecs[7];
#endif

View File

@ -1959,12 +1959,12 @@ void nsHTMLMediaElement::UnbindFromTree(bool aDeep,
}
#ifdef MOZ_RAW
static const char gRawTypes[][16] = {
static const char gRawTypes[2][16] = {
"video/x-raw",
"video/x-raw-yuv"
};
static const char* gRawCodecs[] = {
static const char* gRawCodecs[1] = {
nullptr
};
@ -2048,7 +2048,7 @@ nsHTMLMediaElement::IsOggType(const nsACString& aType)
// See http://www.rfc-editor.org/rfc/rfc2361.txt for the definitions
// of WAVE media types and codec types. However, the audio/vnd.wave
// MIME type described there is not used.
const char nsHTMLMediaElement::gWaveTypes[4][16] = {
const char nsHTMLMediaElement::gWaveTypes[4][15] = {
"audio/x-wav",
"audio/wav",
"audio/wave",
@ -2084,7 +2084,7 @@ nsHTMLMediaElement::IsWaveType(const nsACString& aType)
#endif
#ifdef MOZ_WEBM
const char nsHTMLMediaElement::gWebMTypes[2][17] = {
const char nsHTMLMediaElement::gWebMTypes[2][11] = {
"video/webm",
"audio/webm"
};
@ -2120,7 +2120,7 @@ nsHTMLMediaElement::IsWebMType(const nsACString& aType)
#endif
#ifdef MOZ_GSTREAMER
const char nsHTMLMediaElement::gH264Types[3][17] = {
const char nsHTMLMediaElement::gH264Types[3][16] = {
"video/mp4",
"video/3gpp",
"video/quicktime",

View File

@ -35,7 +35,7 @@ function createTestArray() {
var tests = [];
var tmpVid = document.createElement("video");
for (var testNum=0; testNum<gSeekTests.length; testNum++) {
for (var testNum=0; testNum<gInfoLeakTests.length; testNum++) {
var test = gInfoLeakTests[testNum];
if (!tmpVid.canPlayType(test.type)) {
continue;

View File

@ -16,9 +16,9 @@ DIRS = \
interfaces/base \
interfaces/canvas \
interfaces/core \
interfaces/devicestorage \
interfaces/html \
interfaces/events \
interfaces/devicestorage \
interfaces/contacts \
interfaces/settings \
interfaces/stylesheets \

View File

@ -13,7 +13,6 @@
#include "nsMimeTypeArray.h"
#include "nsDesktopNotification.h"
#include "nsGeolocation.h"
#include "nsDeviceStorage.h"
#include "nsIHttpProtocolHandler.h"
#include "nsICachingChannel.h"
#include "nsIDocShell.h"
@ -192,6 +191,12 @@ Navigator::Invalidate()
}
#endif
PRUint32 len = mDeviceStorageStores.Length();
for (PRUint32 i = 0; i < len; ++i) {
mDeviceStorageStores[i]->Shutdown();
}
mDeviceStorageStores.Clear();
}
nsPIDOMWindow *
@ -873,7 +878,7 @@ Navigator::MozIsLocallyAvailable(const nsAString &aURI,
// Navigator::nsIDOMNavigatorDeviceStorage
//*****************************************************************************
NS_IMETHODIMP Navigator::GetDeviceStorage(const nsAString &aType, nsIVariant** _retval)
NS_IMETHODIMP Navigator::GetDeviceStorage(const nsAString &aType, nsIDOMDeviceStorage** _retval)
{
if (!Preferences::GetBool("device.storage.enabled", false)) {
return NS_OK;
@ -885,7 +890,15 @@ NS_IMETHODIMP Navigator::GetDeviceStorage(const nsAString &aType, nsIVariant** _
return NS_ERROR_FAILURE;
}
nsDOMDeviceStorage::CreateDeviceStoragesFor(win, aType, _retval);
nsRefPtr<nsDOMDeviceStorage> storage;
nsDOMDeviceStorage::CreateDeviceStoragesFor(win, aType, getter_AddRefs(storage));
if (!storage) {
return NS_OK;
}
NS_ADDREF(*_retval = storage.get());
mDeviceStorageStores.AppendElement(storage);
return NS_OK;
}

View File

@ -17,6 +17,7 @@
#include "nsIDOMNavigatorNetwork.h"
#include "nsAutoPtr.h"
#include "nsWeakReference.h"
#include "DeviceStorage.h"
class nsPluginArray;
class nsMimeTypeArray;
@ -162,6 +163,7 @@ private:
#endif
nsRefPtr<nsDOMCameraManager> mCameraManager;
nsCOMPtr<nsIDOMNavigatorSystemMessages> mMessagesManager;
nsTArray<nsRefPtr<nsDOMDeviceStorage> > mDeviceStorageStores;
nsWeakPtr mWindow;
};

View File

@ -140,6 +140,7 @@
#include "nsIDOMEventTarget.h"
// CSS related includes
#include "nsCSSRules.h"
#include "nsIDOMStyleSheet.h"
#include "nsIDOMStyleSheetList.h"
#include "nsIDOMCSSStyleDeclaration.h"
@ -289,6 +290,7 @@
#include "nsIDOMCSSMediaRule.h"
#include "nsIDOMCSSFontFaceRule.h"
#include "nsIDOMCSSMozDocumentRule.h"
#include "nsIDOMCSSSupportsRule.h"
#include "nsIDOMMozCSSKeyframeRule.h"
#include "nsIDOMMozCSSKeyframesRule.h"
#include "nsIDOMCSSPrimitiveValue.h"
@ -418,6 +420,7 @@
// Device Storage
#include "nsIDOMDeviceStorage.h"
#include "nsIDOMDeviceStorageChangeEvent.h"
#include "nsIDOMDeviceStorageCursor.h"
// Drag and drop
@ -1088,6 +1091,9 @@ static nsDOMClassInfoData sClassInfoData[] = {
NS_DEFINE_CLASSINFO_DATA(CSSMozDocumentRule, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(CSSSupportsRule, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(BeforeUnloadEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
@ -1431,7 +1437,10 @@ static nsDOMClassInfoData sClassInfoData[] = {
NS_DEFINE_CLASSINFO_DATA(MessageEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(DeviceStorage, nsDOMGenericSH,
NS_DEFINE_CLASSINFO_DATA(DeviceStorage, nsEventTargetSH,
EVENTTARGET_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(DeviceStorageChangeEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(DeviceStorageCursor, nsDOMGenericSH,
@ -3171,6 +3180,10 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSMozDocumentRule)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(CSSSupportsRule, nsIDOMCSSSupportsRule)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSSupportsRule)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(BeforeUnloadEvent, nsIDOMBeforeUnloadEvent)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMBeforeUnloadEvent)
DOM_CLASSINFO_EVENT_MAP_ENTRIES
@ -4027,6 +4040,12 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_BEGIN(DeviceStorage, nsIDOMDeviceStorage)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMDeviceStorage)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(DeviceStorageChangeEvent, nsIDOMDeviceStorageChangeEvent)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMDeviceStorageChangeEvent)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEvent)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(DeviceStorageCursor, nsIDOMDeviceStorageCursor)
@ -5815,16 +5834,12 @@ DefineInterfaceConstants(JSContext *cx, JSObject *obj, const nsIID *aIID)
}
case nsXPTType::T_I32:
{
if (!JS_NewNumberValue(cx, c->GetValue()->val.i32, &v)) {
return NS_ERROR_UNEXPECTED;
}
v = JS_NumberValue(c->GetValue()->val.i32);
break;
}
case nsXPTType::T_U32:
{
if (!JS_NewNumberValue(cx, c->GetValue()->val.u32, &v)) {
return NS_ERROR_UNEXPECTED;
}
v = JS_NumberValue(c->GetValue()->val.u32);
break;
}
default:
@ -6697,6 +6712,13 @@ ConstructorEnabled(const nsGlobalNameStruct *aStruct, nsGlobalWindow *aWin)
}
}
// Don't expose CSSSupportsRule unless @supports processing is enabled.
if (aStruct->mDOMClassInfoID == eDOMClassInfo_CSSSupportsRule_id) {
if (!CSSSupportsRule::PrefEnabled()) {
return false;
}
}
return true;
}

View File

@ -193,6 +193,7 @@ DOMCI_CLASS(TreeColumns)
#endif
DOMCI_CLASS(CSSMozDocumentRule)
DOMCI_CLASS(CSSSupportsRule)
DOMCI_CLASS(BeforeUnloadEvent)
@ -384,6 +385,7 @@ DOMCI_CLASS(DataContainerEvent)
DOMCI_CLASS(MessageEvent)
DOMCI_CLASS(DeviceStorage)
DOMCI_CLASS(DeviceStorageChangeEvent)
DOMCI_CLASS(DeviceStorageCursor)
// Geolocation

View File

@ -8349,7 +8349,8 @@ nsGlobalWindow::GetIndexedDB(nsIIDBFactory** _retval)
}
// This may be null if being created from a file.
rv = indexedDB::IDBFactory::Create(this, getter_AddRefs(mIndexedDB));
rv = indexedDB::IDBFactory::Create(this, nullptr,
getter_AddRefs(mIndexedDB));
NS_ENSURE_SUCCESS(rv, rv);
}

View File

@ -2412,8 +2412,7 @@ nsJSContext::AddSupportsPrimitiveTojsvals(nsISupports *aArg, jsval *aArgv)
p->GetData(&data);
JSBool ok = ::JS_NewNumberValue(cx, data, aArgv);
NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
*aArgv = ::JS_NumberValue(data);
break;
}
@ -2425,8 +2424,7 @@ nsJSContext::AddSupportsPrimitiveTojsvals(nsISupports *aArg, jsval *aArgv)
p->GetData(&data);
JSBool ok = ::JS_NewNumberValue(cx, data, aArgv);
NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
*aArgv = ::JS_NumberValue(data);
break;
}

View File

@ -2056,9 +2056,9 @@ for (uint32_t i = 0; i < length; ++i) {
"%s.SetNull()" % varName)
return handleDefault(
conversionCode,
("static const PRUnichar data[] = { %s, 0 };\n"
("static const PRUnichar data[] = { %s };\n"
"%s.SetData(data, ArrayLength(data) - 1)" %
(", ".join("'" + char + "'" for char in defaultValue.value),
(", ".join(["'" + char + "'" for char in defaultValue.value] + ["0"]),
varName)))
if isMember:
@ -2586,7 +2586,7 @@ if (!%(resultStr)s) {
IDLType.Tags.double]:
# XXXbz will cast to double do the "even significand" thing that webidl
# calls for for 64-bit ints? Do we care?
return wrapAndSetPtr("JS_NewNumberValue(cx, double(%s), ${jsvalPtr})" % result)
return setValue("JS_NumberValue(double(%s))" % result)
elif tag == IDLType.Tags.uint32:
return setValue("UINT_TO_JSVAL(%s)" % result)

View File

@ -357,6 +357,7 @@ dictionary Dict : ParentDict {
long b = 8;
long z = 9;
DOMString str;
DOMString empty = "";
TestEnum otherEnum = "b";
DOMString otherStr = "def";
DOMString? yetAnotherStr = null;

View File

@ -154,9 +154,9 @@ BluetoothAdapter::SetPropertyByValue(const BluetoothNamedValue& aValue)
if (sc) {
rv =
StringArrayToJSArray(sc->GetNativeContext(),
sc->GetNativeGlobal(), mUuids, &mJsDeviceAddresses);
sc->GetNativeGlobal(), mDeviceAddresses, &mJsDeviceAddresses);
if (NS_FAILED(rv)) {
NS_WARNING("Cannot set JS Devices Addresses object!");
NS_WARNING("Cannot set JS Device Addresses object!");
return;
}
Root();
@ -335,7 +335,7 @@ BluetoothAdapter::GetDevices(JSContext* aCx, jsval* aDevices)
aDevices->setObject(*mJsDeviceAddresses);
}
else {
NS_WARNING("UUIDs not yet set!\n");
NS_WARNING("Devices not yet set!\n");
return NS_ERROR_FAILURE;
}
return NS_OK;

View File

@ -50,12 +50,10 @@ ParseZoomRatioItemAndAdd(JSContext* aCx, JSObject* aArray, PRUint32 aIndex, cons
}
double d = strtod(aStart, aEnd);
jsval v;
d /= 100;
if (!JS_NewNumberValue(aCx, d, &v)) {
return NS_ERROR_FAILURE;
}
jsval v = JS_NumberValue(d);
if (!JS_SetElement(aCx, aArray, aIndex, &v)) {
return NS_ERROR_FAILURE;
}

View File

@ -0,0 +1,73 @@
/* 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 DeviceStorage_h
#define DeviceStorage_h
#include "nsIDOMDeviceStorage.h"
#include "nsIFile.h"
#include "nsIObserver.h"
#include "nsDOMEventTargetHelper.h"
class nsDOMDeviceStorage MOZ_FINAL
: public nsIDOMDeviceStorage
, public nsIFileUpdateListener
, public nsDOMEventTargetHelper
, public nsIObserver
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMDEVICESTORAGE
NS_DECL_NSIFILEUPDATELISTENER
NS_DECL_NSIOBSERVER
NS_DECL_NSIDOMEVENTTARGET
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMDeviceStorage, nsDOMEventTargetHelper)
NS_DECL_EVENT_HANDLER(change)
nsDOMDeviceStorage();
nsresult Init(nsPIDOMWindow* aWindow, const nsAString &aType);
void SetRootFileForType(const nsAString& aType);
static void CreateDeviceStoragesFor(nsPIDOMWindow* aWin,
const nsAString &aType,
nsDOMDeviceStorage** aStore);
void Shutdown();
private:
~nsDOMDeviceStorage();
nsresult GetInternal(const JS::Value & aName,
JSContext* aCx,
nsIDOMDOMRequest** aRetval,
bool aEditable);
nsresult EnumerateInternal(const JS::Value & aName,
const JS::Value & aOptions,
JSContext* aCx,
PRUint8 aArgc,
bool aEditable,
nsIDOMDeviceStorageCursor** aRetval);
PRInt32 mStorageType;
nsCOMPtr<nsIFile> mFile;
nsCOMPtr<nsIURI> mURI;
friend class WatchFileEvent;
friend class DeviceStorageRequest;
bool mIsWatchingFile;
// nsIDOMDeviceStorage.type
enum {
DEVICE_STORAGE_TYPE_DEFAULT = 0,
DEVICE_STORAGE_TYPE_SHARED,
DEVICE_STORAGE_TYPE_EXTERNAL,
};
};
#endif

View File

@ -31,7 +31,7 @@ CPPSRCS = \
$(NULL)
EXPORTS = \
nsDeviceStorage.h \
DeviceStorage.h \
$(NULL)
LOCAL_INCLUDES = \

View File

@ -2,7 +2,15 @@
* 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 "mozilla/dom/ContentChild.h"
#include "mozilla/dom/PBrowserChild.h"
#include "mozilla/dom/devicestorage/PDeviceStorageRequestChild.h"
#include "mozilla/Attributes.h"
#include "mozilla/dom/PContentPermissionRequestChild.h"
#include "nsDeviceStorage.h"
#include "nsDOMEvent.h"
#include "nsServiceManagerUtils.h"
#include "nsIFile.h"
#include "nsIDirectoryEnumerator.h"
@ -21,6 +29,10 @@
#include "nsXULAppAPI.h"
#include "TabChild.h"
#include "DeviceStorageRequestChild.h"
#include "nsIDOMDeviceStorageChangeEvent.h"
#include "nsCRT.h"
#include "mozilla/Services.h"
#include "nsIObserverService.h"
// Microsoft's API Name hackery sucks
#undef CreateEvent
@ -90,8 +102,8 @@ DeviceStorageFile::IsSafePath()
while ((token = nsCRT::strtok(buffer, "/", &buffer))) {
if (PL_strcmp(token, "") == 0 ||
PL_strcmp(token, ".") == 0 ||
PL_strcmp(token, "..") == 0 ) {
PL_strcmp(token, ".") == 0 ||
PL_strcmp(token, "..") == 0 ) {
return false;
}
}
@ -153,8 +165,8 @@ DeviceStorageFile::Write(nsIDOMBlob* aBlob)
nsCOMPtr<nsIOutputStream> bufferedOutputStream;
NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream),
outputStream,
4096*4);
outputStream,
4096*4);
if (!bufferedOutputStream) {
return NS_ERROR_FAILURE;
@ -197,18 +209,21 @@ DeviceStorageFile::Write(InfallibleTArray<PRUint8>& aBits) {
void
DeviceStorageFile::CollectFiles(nsTArray<nsRefPtr<DeviceStorageFile> > &aFiles,
PRUint64 aSince)
PRUint64 aSince)
{
nsString rootPath;
mFile->GetPath(rootPath);
nsresult rv = mFile->GetPath(rootPath);
if (NS_FAILED(rv)) {
return;
}
return collectFilesInternal(aFiles, aSince, rootPath);
}
void
DeviceStorageFile::collectFilesInternal(nsTArray<nsRefPtr<DeviceStorageFile> > &aFiles,
PRUint64 aSince,
nsAString& aRootPath)
PRUint64 aSince,
nsAString& aRootPath)
{
nsCOMPtr<nsISimpleEnumerator> e;
mFile->GetDirectoryEntries(getter_AddRefs(e));
@ -236,7 +251,10 @@ DeviceStorageFile::collectFilesInternal(nsTArray<nsRefPtr<DeviceStorageFile> > &
f->IsFile(&isFile);
nsString fullpath;
f->GetPath(fullpath);
nsresult rv = f->GetPath(fullpath);
if (NS_FAILED(rv)) {
continue;
}
if (!StringBeginsWith(fullpath, aRootPath)) {
NS_ERROR("collectFiles returned a path that does not belong!");
@ -261,14 +279,9 @@ DeviceStorageFile::collectFilesInternal(nsTArray<nsRefPtr<DeviceStorageFile> > &
NS_IMPL_THREADSAFE_ISUPPORTS0(DeviceStorageFile)
// TODO - eventually, we will want to factor this method
// out into different system specific subclasses (or
// something)
PRInt32
nsDOMDeviceStorage::SetRootFileForType(const nsAString& aType, const PRInt32 aIndex)
void
nsDOMDeviceStorage::SetRootFileForType(const nsAString& aType)
{
PRInt32 typeResult = DEVICE_STORAGE_TYPE_DEFAULT;
nsCOMPtr<nsIFile> f;
nsCOMPtr<nsIProperties> dirService = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
NS_ASSERTION(dirService, "Must have directory service");
@ -278,72 +291,54 @@ nsDOMDeviceStorage::SetRootFileForType(const nsAString& aType, const PRInt32 aIn
nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID);
if (!vs) {
return typeResult;
return;
}
nsCOMPtr<nsIVolume> v;
vs->GetVolumeByPath(NS_LITERAL_STRING("/sdcard"), getter_AddRefs(v));
if (!v) {
return typeResult;
return;
}
PRInt32 state;
v->GetState(&state);
if (state != nsIVolume::STATE_MOUNTED) {
return typeResult;
return;
}
#endif
// Picture directory
if (aType.Equals(NS_LITERAL_STRING("pictures"))) {
#ifdef MOZ_WIDGET_GONK
if (aIndex == 0) {
NS_NewLocalFile(NS_LITERAL_STRING("/sdcard/DCIM"), false, getter_AddRefs(f));
}
NS_NewLocalFile(NS_LITERAL_STRING("/sdcard/DCIM"), false, getter_AddRefs(f));
#elif defined (MOZ_WIDGET_COCOA)
if (aIndex == 0) {
dirService->Get(NS_OSX_PICTURE_DOCUMENTS_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
}
dirService->Get(NS_OSX_PICTURE_DOCUMENTS_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
#elif defined (XP_UNIX)
if (aIndex == 0) {
dirService->Get(NS_UNIX_XDG_PICTURES_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
}
dirService->Get(NS_UNIX_XDG_PICTURES_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
#endif
}
// Video directory
if (aType.Equals(NS_LITERAL_STRING("videos"))) {
#ifdef MOZ_WIDGET_GONK
if (aIndex == 0) {
NS_NewLocalFile(NS_LITERAL_STRING("/sdcard/Movies"), false, getter_AddRefs(f));
}
NS_NewLocalFile(NS_LITERAL_STRING("/sdcard/Movies"), false, getter_AddRefs(f));
#elif defined (MOZ_WIDGET_COCOA)
if (aIndex == 0) {
dirService->Get(NS_OSX_MOVIE_DOCUMENTS_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
}
dirService->Get(NS_OSX_MOVIE_DOCUMENTS_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
#elif defined (XP_UNIX)
if (aIndex == 0) {
dirService->Get(NS_UNIX_XDG_VIDEOS_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
}
dirService->Get(NS_UNIX_XDG_VIDEOS_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
#endif
}
// Music directory
if (aType.Equals(NS_LITERAL_STRING("music"))) {
#ifdef MOZ_WIDGET_GONK
if (aIndex == 0) {
NS_NewLocalFile(NS_LITERAL_STRING("/sdcard/Music"), false, getter_AddRefs(f));
}
NS_NewLocalFile(NS_LITERAL_STRING("/sdcard/Music"), false, getter_AddRefs(f));
#elif defined (MOZ_WIDGET_COCOA)
if (aIndex == 0) {
dirService->Get(NS_OSX_MUSIC_DOCUMENTS_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
}
dirService->Get(NS_OSX_MUSIC_DOCUMENTS_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
#elif defined (XP_UNIX)
if (aIndex == 0) {
dirService->Get(NS_UNIX_XDG_MUSIC_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
}
dirService->Get(NS_UNIX_XDG_MUSIC_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
#endif
}
@ -351,17 +346,17 @@ nsDOMDeviceStorage::SetRootFileForType(const nsAString& aType, const PRInt32 aIn
if (mozilla::Preferences::GetBool("device.storage.testing", false)) {
// testing directory
if (aType.Equals(NS_LITERAL_STRING("testing")) && aIndex == 0) {
if (aType.Equals(NS_LITERAL_STRING("testing"))) {
dirService->Get(NS_OS_TEMP_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
if (f) {
f->AppendRelativeNativePath(NS_LITERAL_CSTRING("device-storage-testing"));
f->Create(nsIFile::DIRECTORY_TYPE, 0777);
f->Normalize();
}
}
}
mFile = f;
return typeResult;
}
static jsval nsIFileToJsval(nsPIDOMWindow* aWindow, DeviceStorageFile* aFile)
@ -443,6 +438,92 @@ jsval StringToJsval(nsPIDOMWindow* aWindow, nsAString& aString)
return result;
}
class nsDOMDeviceStorageChangeEvent : public nsDOMEvent, public nsIDOMDeviceStorageChangeEvent
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_FORWARD_NSIDOMEVENT(nsDOMEvent::)
NS_DECL_NSIDOMDEVICESTORAGECHANGEEVENT
nsDOMDeviceStorageChangeEvent();
virtual nsresult InitFromCtor(const nsAString& aType,
JSContext* aCx,
jsval* aVal);
NS_IMETHOD Init(const nsAString & aEventTypeArg,
bool aCanBubbleArg,
bool aCancelableArg,
nsAString& aPath,
nsAString& aReason);
private:
~nsDOMDeviceStorageChangeEvent();
protected:
nsString mPath;
nsString mReason;
};
DOMCI_DATA(DeviceStorageChangeEvent, nsDOMDeviceStorageChangeEvent)
NS_INTERFACE_MAP_BEGIN(nsDOMDeviceStorageChangeEvent)
NS_INTERFACE_MAP_ENTRY(nsIDOMDeviceStorageChangeEvent)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DeviceStorageChangeEvent)
NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
NS_IMPL_ADDREF_INHERITED(nsDOMDeviceStorageChangeEvent, nsDOMEvent)
NS_IMPL_RELEASE_INHERITED(nsDOMDeviceStorageChangeEvent, nsDOMEvent)
nsDOMDeviceStorageChangeEvent::nsDOMDeviceStorageChangeEvent()
: nsDOMEvent(nullptr, nullptr)
{
}
nsDOMDeviceStorageChangeEvent::~nsDOMDeviceStorageChangeEvent()
{
}
NS_IMETHODIMP
nsDOMDeviceStorageChangeEvent::Init(const nsAString & aEventTypeArg,
bool aCanBubbleArg,
bool aCancelableArg,
nsAString& aPath,
nsAString& aReason)
{
nsresult rv = nsDOMEvent::InitEvent(aEventTypeArg, aCanBubbleArg, aCancelableArg);
NS_ENSURE_SUCCESS(rv, rv);
mPath = aPath;
mReason = aReason;
return NS_OK;
}
nsresult
nsDOMDeviceStorageChangeEvent::InitFromCtor(const nsAString& aType,
JSContext* aCx,
jsval* aVal)
{
mozilla::dom::DeviceStorageChangeEventInit d;
nsresult rv = d.Init(aCx, aVal);
NS_ENSURE_SUCCESS(rv, rv);
return Init(aType, d.bubbles, d.cancelable, d.path, d.reason);
}
NS_IMETHODIMP
nsDOMDeviceStorageChangeEvent::GetPath(nsAString & aPath)
{
aPath = mPath;
return NS_OK;
}
NS_IMETHODIMP
nsDOMDeviceStorageChangeEvent::GetReason(nsAString & aReason)
{
aReason = mReason;
return NS_OK;
}
class DeviceStorageCursorRequest MOZ_FINAL
: public nsIContentPermissionRequest
, public PCOMContentPermissionRequestChild
@ -488,11 +569,11 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(DeviceStorageCursorRequest)
NS_IMPL_CYCLE_COLLECTION_CLASS(DeviceStorageCursorRequest)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DeviceStorageCursorRequest)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCursor)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCursor)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DeviceStorageCursorRequest)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mCursor, nsIDOMDeviceStorageCursor)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mCursor, nsIDOMDeviceStorageCursor)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@ -707,7 +788,12 @@ nsDOMDeviceStorageCursor::Allow()
if (XRE_GetProcessType() != GeckoProcessType_Default) {
nsString fullpath;
mFile->mFile->GetPath(fullpath);
nsresult rv = mFile->mFile->GetPath(fullpath);
if (NS_FAILED(rv)) {
// just do nothing
return NS_OK;
}
PDeviceStorageRequestChild* child = new DeviceStorageRequestChild(this, mFile);
DeviceStorageEnumerationParams params(fullpath, mSince);
@ -827,14 +913,14 @@ public:
mFile->mFile->Remove(false);
nsCOMPtr<PostErrorEvent> event = new PostErrorEvent(mRequest,
POST_ERROR_EVENT_UNKNOWN,
mFile);
POST_ERROR_EVENT_UNKNOWN,
mFile);
NS_DispatchToMainThread(event);
return NS_OK;
}
nsCOMPtr<PostResultEvent> event = new PostResultEvent(mRequest,
mFile->mPath);
mFile->mPath);
NS_DispatchToMainThread(event);
return NS_OK;
@ -927,23 +1013,40 @@ class DeviceStorageRequest MOZ_FINAL
{
public:
enum {
enum DeviceStorageRequestType {
DEVICE_STORAGE_REQUEST_READ,
DEVICE_STORAGE_REQUEST_WRITE,
DEVICE_STORAGE_REQUEST_DELETE
DEVICE_STORAGE_REQUEST_DELETE,
DEVICE_STORAGE_REQUEST_WATCH
};
DeviceStorageRequest(const PRInt32 aRequestType,
DeviceStorageRequest(const DeviceStorageRequestType aRequestType,
nsPIDOMWindow *aWindow,
nsIURI *aURI,
DeviceStorageFile *aFile,
DOMRequest* aRequest,
nsDOMDeviceStorage *aDeviceStorage,
nsIDOMEventListener *aListener)
: mRequestType(aRequestType)
, mWindow(aWindow)
, mURI(aURI)
, mFile(aFile)
, mRequest(aRequest)
, mDeviceStorage(aDeviceStorage)
, mListener(aListener) {}
DeviceStorageRequest(const DeviceStorageRequestType aRequestType,
nsPIDOMWindow *aWindow,
nsIURI *aURI,
DeviceStorageFile *aFile,
DOMRequest* aRequest,
nsIDOMBlob *aBlob = nullptr)
: mRequestType(aRequestType)
, mWindow(aWindow)
, mURI(aURI)
, mFile(aFile)
, mRequest(aRequest)
, mBlob(aBlob) {}
: mRequestType(aRequestType)
, mWindow(aWindow)
, mURI(aURI)
, mFile(aFile)
, mRequest(aRequest)
, mBlob(aBlob) {}
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(DeviceStorageRequest, nsIContentPermissionRequest)
@ -960,8 +1063,9 @@ public:
// because owner implements nsITabChild, we can assume that it is
// the one and only TabChild.
TabChild* child = GetTabChildFrom(mWindow->GetDocShell());
if (!child)
if (!child) {
return NS_OK;
}
// Retain a reference so the object isn't deleted without IPDL's knowledge.
// Corresponding release occurs in DeallocPContentPermissionRequest.
@ -1023,7 +1127,12 @@ public:
}
nsString fullpath;
mFile->mFile->GetPath(fullpath);
nsresult rv = mFile->mFile->GetPath(fullpath);
if (NS_FAILED(rv)) {
// just do nothing
return NS_OK;
}
switch(mRequestType) {
case DEVICE_STORAGE_REQUEST_WRITE:
@ -1032,52 +1141,74 @@ public:
return NS_ERROR_FAILURE;
}
if (XRE_GetProcessType() != GeckoProcessType_Default) {
PDeviceStorageRequestChild* child = new DeviceStorageRequestChild(mRequest, mFile);
if (XRE_GetProcessType() != GeckoProcessType_Default) {
PDeviceStorageRequestChild* child = new DeviceStorageRequestChild(mRequest, mFile);
nsCOMPtr<nsIInputStream> stream;
mBlob->GetInternalStream(getter_AddRefs(stream));
nsCOMPtr<nsIInputStream> stream;
mBlob->GetInternalStream(getter_AddRefs(stream));
InfallibleTArray<PRUint8> bits;
PRUint32 bufSize, numRead;
InfallibleTArray<PRUint8> bits;
PRUint32 bufSize, numRead;
stream->Available(&bufSize);
bits.SetCapacity(bufSize);
stream->Available(&bufSize);
bits.SetCapacity(bufSize);
void* buffer = (void*) bits.Elements();
void* buffer = (void*) bits.Elements();
stream->Read((char*)buffer, bufSize, &numRead);
stream->Read((char*)buffer, bufSize, &numRead);
DeviceStorageAddParams params(fullpath, bits);
ContentChild::GetSingleton()->SendPDeviceStorageRequestConstructor(child, params);
return NS_OK;
}
r = new WriteFileEvent(mBlob, mFile, mRequest);
DeviceStorageAddParams params(fullpath, bits);
ContentChild::GetSingleton()->SendPDeviceStorageRequestConstructor(child, params);
return NS_OK;
}
r = new WriteFileEvent(mBlob, mFile, mRequest);
break;
}
case DEVICE_STORAGE_REQUEST_READ:
{
if (XRE_GetProcessType() != GeckoProcessType_Default) {
PDeviceStorageRequestChild* child = new DeviceStorageRequestChild(mRequest, mFile);
DeviceStorageGetParams params(fullpath);
ContentChild::GetSingleton()->SendPDeviceStorageRequestConstructor(child, params);
return NS_OK;
}
if (XRE_GetProcessType() != GeckoProcessType_Default) {
PDeviceStorageRequestChild* child = new DeviceStorageRequestChild(mRequest, mFile);
DeviceStorageGetParams params(fullpath);
ContentChild::GetSingleton()->SendPDeviceStorageRequestConstructor(child, params);
return NS_OK;
}
r = new ReadFileEvent(mFile, mRequest);
break;
}
case DEVICE_STORAGE_REQUEST_DELETE:
{
if (XRE_GetProcessType() != GeckoProcessType_Default) {
PDeviceStorageRequestChild* child = new DeviceStorageRequestChild(mRequest, mFile);
DeviceStorageDeleteParams params(fullpath);
ContentChild::GetSingleton()->SendPDeviceStorageRequestConstructor(child, params);
return NS_OK;
}
if (XRE_GetProcessType() != GeckoProcessType_Default) {
PDeviceStorageRequestChild* child = new DeviceStorageRequestChild(mRequest, mFile);
DeviceStorageDeleteParams params(fullpath);
ContentChild::GetSingleton()->SendPDeviceStorageRequestConstructor(child, params);
return NS_OK;
}
r = new DeleteFileEvent(mFile, mRequest);
break;
}
case DEVICE_STORAGE_REQUEST_WATCH:
{
if (XRE_GetProcessType() != GeckoProcessType_Default) {
nsString fullpath;
mFile->mFile->GetPath(fullpath);
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
obs->AddObserver(mDeviceStorage, "file-watcher-update", false);
ContentChild::GetSingleton()->SendAddFileWatch(fullpath);
} else {
if (!mDeviceStorage->mIsWatchingFile) {
//TODO
mFile->mFile->Watch(mDeviceStorage);
mDeviceStorage->mIsWatchingFile = true;
}
}
return NS_OK;
}
}
if (r) {
@ -1112,6 +1243,8 @@ private:
nsRefPtr<DOMRequest> mRequest;
nsCOMPtr<nsIDOMBlob> mBlob;
nsRefPtr<nsDOMDeviceStorage> mDeviceStorage;
nsCOMPtr<nsIDOMEventListener> mListener;
};
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DeviceStorageRequest)
@ -1128,44 +1261,55 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DeviceStorageRequest)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mRequest)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mWindow)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mBlob)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDeviceStorage)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mListener)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DeviceStorageRequest)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mRequest, nsIDOMDOMRequest)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mWindow, nsPIDOMWindow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mBlob, nsIDOMBlob)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mDeviceStorage, nsIDOMDeviceStorage)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mListener, nsIDOMEventListener)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMDeviceStorage)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMDeviceStorage, nsDOMEventTargetHelper)
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(change)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMDeviceStorage, nsDOMEventTargetHelper)
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(change)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
DOMCI_DATA(DeviceStorage, nsDOMDeviceStorage)
NS_INTERFACE_MAP_BEGIN(nsDOMDeviceStorage)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMDeviceStorage)
NS_INTERFACE_MAP_ENTRY(nsIDOMDeviceStorage)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMDeviceStorage)
NS_INTERFACE_MAP_ENTRY(nsIFileUpdateListener)
NS_INTERFACE_MAP_ENTRY(nsIObserver)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DeviceStorage)
NS_INTERFACE_MAP_END
NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
NS_IMPL_THREADSAFE_ADDREF(nsDOMDeviceStorage)
NS_IMPL_THREADSAFE_RELEASE(nsDOMDeviceStorage)
NS_IMPL_ADDREF_INHERITED(nsDOMDeviceStorage, nsDOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(nsDOMDeviceStorage, nsDOMEventTargetHelper)
nsDOMDeviceStorage::nsDOMDeviceStorage()
: mStorageType(DEVICE_STORAGE_TYPE_DEFAULT)
{
}
: mIsWatchingFile(false)
{ }
nsresult
nsDOMDeviceStorage::Init(nsPIDOMWindow* aWindow, const nsAString &aType, const PRInt32 aIndex)
nsDOMDeviceStorage::Init(nsPIDOMWindow* aWindow, const nsAString &aType)
{
NS_ASSERTION(aWindow, "Must have a content dom");
mStorageType = SetRootFileForType(aType, aIndex);
SetRootFileForType(aType);
if (!mFile) {
return NS_ERROR_NOT_AVAILABLE;
}
mOwner = do_GetWeakReference(aWindow);
if (!mOwner) {
return NS_ERROR_FAILURE;
}
BindToOwner(aWindow);
// Grab the uri of the document
nsCOMPtr<nsIDOMDocument> domdoc;
@ -1183,50 +1327,34 @@ nsDOMDeviceStorage::~nsDOMDeviceStorage()
}
void
nsDOMDeviceStorage::CreateDeviceStoragesFor(nsPIDOMWindow* aWin,
const nsAString &aType,
nsIVariant** _retval)
nsDOMDeviceStorage::Shutdown()
{
nsTArray<nsRefPtr<nsIDOMDeviceStorage> > stores;
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
PRInt32 index = 0;
while (1) {
nsresult rv;
nsRefPtr<nsDOMDeviceStorage> storage = new nsDOMDeviceStorage();
rv = storage->Init(aWin, aType, index++);
if (NS_FAILED(rv))
break;
stores.AppendElement(storage);
if (mIsWatchingFile) {
if (XRE_GetProcessType() != GeckoProcessType_Default) {
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
obs->RemoveObserver(this, "file-watcher-update");
nsString fullpath;
mFile->GetPath(fullpath);
ContentChild::GetSingleton()->SendRemoveFileWatch(fullpath);
}
else {
mFile->Unwatch(this);
}
}
nsCOMPtr<nsIWritableVariant> result = do_CreateInstance("@mozilla.org/variant;1");
if (!result) {
return;
}
result->SetAsArray(nsIDataType::VTYPE_INTERFACE,
&NS_GET_IID(nsIDOMDeviceStorage),
stores.Length(),
const_cast<void*>(static_cast<const void*>(stores.Elements())));
NS_ADDREF(*_retval = result);
}
NS_IMETHODIMP
nsDOMDeviceStorage::GetType(nsAString & aType)
void
nsDOMDeviceStorage::CreateDeviceStoragesFor(nsPIDOMWindow* aWin,
const nsAString &aType,
nsDOMDeviceStorage** aStore)
{
switch(mStorageType) {
case DEVICE_STORAGE_TYPE_EXTERNAL:
aType.AssignLiteral("external");
break;
case DEVICE_STORAGE_TYPE_SHARED:
aType.AssignLiteral("shared");
break;
case DEVICE_STORAGE_TYPE_DEFAULT:
default:
aType.AssignLiteral("default");
break;
nsRefPtr<nsDOMDeviceStorage> storage = new nsDOMDeviceStorage();
if (NS_SUCCEEDED(storage->Init(aWin, aType))) {
NS_ADDREF(*aStore = storage);
}
return NS_OK;
}
NS_IMETHODIMP
@ -1251,7 +1379,7 @@ nsDOMDeviceStorage::AddNamed(nsIDOMBlob *aBlob,
if (aBlob == nullptr)
return NS_OK;
nsCOMPtr<nsPIDOMWindow> win = do_QueryReferent(mOwner);
nsCOMPtr<nsPIDOMWindow> win = GetOwner();
if (!win) {
return NS_ERROR_UNEXPECTED;
}
@ -1296,7 +1424,7 @@ nsDOMDeviceStorage::GetInternal(const JS::Value & aPath,
nsIDOMDOMRequest * *_retval,
bool aEditable)
{
nsCOMPtr<nsPIDOMWindow> win = do_QueryReferent(mOwner);
nsCOMPtr<nsPIDOMWindow> win = GetOwner();
if (!win) {
return NS_ERROR_UNEXPECTED;
}
@ -1335,7 +1463,7 @@ nsDOMDeviceStorage::Delete(const JS::Value & aPath, JSContext* aCx, nsIDOMDOMReq
{
nsCOMPtr<nsIRunnable> r;
nsCOMPtr<nsPIDOMWindow> win = do_QueryReferent(mOwner);
nsCOMPtr<nsPIDOMWindow> win = GetOwner();
if (!win) {
return NS_ERROR_UNEXPECTED;
}
@ -1411,7 +1539,7 @@ nsDOMDeviceStorage::EnumerateInternal(const JS::Value & aName,
bool aEditable,
nsIDOMDeviceStorageCursor** aRetval)
{
nsCOMPtr<nsPIDOMWindow> win = do_QueryReferent(mOwner);
nsCOMPtr<nsPIDOMWindow> win = GetOwner();
if (!win)
return NS_ERROR_UNEXPECTED;
@ -1478,3 +1606,206 @@ nsDOMDeviceStorage::EnumerateInternal(const JS::Value & aName,
return NS_OK;
}
NS_IMETHODIMP
nsDOMDeviceStorage::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *aData)
{
// data strings will have the format of
// reason:path
nsDependentString data(aData);
nsAString::const_iterator start, end;
nsAString::const_iterator colon;
data.BeginReading(start);
data.EndReading(end);
colon = end;
nsString reason;
nsString filepath;
if (!FindInReadable(NS_LITERAL_STRING(":"), start, colon)) {
return NS_OK;
}
filepath = Substring(colon, end);
data.BeginReading(start);
reason = Substring(start, --colon);
nsCOMPtr<nsIFile> f;
NS_NewLocalFile(filepath, false, getter_AddRefs(f));
nsCString creason;
creason.AssignWithConversion(reason);
CopyUTF16toUTF8(reason, creason);
Update(creason.get(), f);
return NS_OK;
}
NS_IMETHODIMP
nsDOMDeviceStorage::Update(const char* aReason, nsIFile* aFile)
{
nsString rootpath;
nsresult rv = mFile->GetPath(rootpath);
if (NS_FAILED(rv)) {
return NS_OK;
}
nsString fullpath;
rv = aFile->GetPath(fullpath);
if (NS_FAILED(rv)) {
return NS_OK;
}
NS_ASSERTION(fullpath.Length() >= rootpath.Length(), "Root path longer than full path!");
if (!StringBeginsWith(fullpath, rootpath)) {
NS_WARNING("Observing a path outside of our root!");
return NS_OK;
}
nsAString::size_type len = rootpath.Length() + 1; // +1 for the trailing /
nsDependentSubstring newPath (fullpath, len, fullpath.Length() - len);
nsRefPtr<nsDOMDeviceStorageChangeEvent> event = new nsDOMDeviceStorageChangeEvent();
nsString reason;
reason.AssignWithConversion(aReason);
rv = event->Init(NS_LITERAL_STRING("change"), true, false, newPath, reason);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOMDeviceStorageChangeEvent> e = event.get();
bool ignore;
DispatchEvent(e, &ignore);
return NS_OK;
}
NS_IMETHODIMP
nsDOMDeviceStorage::AddEventListener(const nsAString & aType,
nsIDOMEventListener *aListener,
bool aUseCapture,
bool aWantsUntrusted,
PRUint8 aArgc)
{
nsCOMPtr<nsPIDOMWindow> win = GetOwner();
if (!win) {
return NS_ERROR_UNEXPECTED;
}
nsRefPtr<DOMRequest> request = new DOMRequest(win);
nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mFile);
nsCOMPtr<nsIRunnable> r = new DeviceStorageRequest(DeviceStorageRequest::DEVICE_STORAGE_REQUEST_WATCH,
win, mURI, dsf, request, this, aListener);
NS_DispatchToMainThread(r);
return nsDOMEventTargetHelper::AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted, aArgc);
}
NS_IMETHODIMP
nsDOMDeviceStorage::AddSystemEventListener(const nsAString & aType,
nsIDOMEventListener *aListener,
bool aUseCapture,
bool aWantsUntrusted,
PRUint8 aArgc)
{
return nsDOMDeviceStorage::AddEventListener(aType,aListener,aUseCapture,aWantsUntrusted, aArgc);
}
NS_IMETHODIMP
nsDOMDeviceStorage::RemoveEventListener(const nsAString & aType,
nsIDOMEventListener *aListener,
bool aUseCapture)
{
nsDOMEventTargetHelper::RemoveEventListener(aType, aListener, false);
if (mIsWatchingFile && !HasListenersFor(NS_LITERAL_STRING("change"))) {
if (XRE_GetProcessType() != GeckoProcessType_Default) {
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
obs->RemoveObserver(this, "file-watcher-update");
nsString fullpath;
mFile->GetPath(fullpath);
ContentChild::GetSingleton()->SendRemoveFileWatch(fullpath);
} else {
mFile->Unwatch(this);
}
}
return NS_OK;
}
NS_IMETHODIMP
nsDOMDeviceStorage::RemoveSystemEventListener(const nsAString & aType,
nsIDOMEventListener *aListener,
bool aUseCapture)
{
return nsDOMDeviceStorage::RemoveEventListener(aType, aListener, aUseCapture);
}
NS_IMETHODIMP
nsDOMDeviceStorage::DispatchEvent(nsIDOMEvent *aEvt,
bool *aRetval)
{
return nsDOMEventTargetHelper::DispatchEvent(aEvt, aRetval);
}
nsIDOMEventTarget *
nsDOMDeviceStorage::GetTargetForDOMEvent()
{
return nsDOMEventTargetHelper::GetTargetForDOMEvent();
}
nsIDOMEventTarget *
nsDOMDeviceStorage::GetTargetForEventTargetChain()
{
return nsDOMEventTargetHelper::GetTargetForEventTargetChain();
}
nsresult
nsDOMDeviceStorage::PreHandleEvent(nsEventChainPreVisitor & aVisitor)
{
return nsDOMEventTargetHelper::PreHandleEvent(aVisitor);
}
nsresult
nsDOMDeviceStorage::WillHandleEvent(nsEventChainPostVisitor & aVisitor)
{
return nsDOMEventTargetHelper::WillHandleEvent(aVisitor);
}
nsresult
nsDOMDeviceStorage::PostHandleEvent(nsEventChainPostVisitor & aVisitor)
{
return nsDOMEventTargetHelper::PostHandleEvent(aVisitor);
}
nsresult
nsDOMDeviceStorage::DispatchDOMEvent(nsEvent *aEvent,
nsIDOMEvent *aDOMEvent,
nsPresContext *aPresContext,
nsEventStatus *aEventStatus)
{
return nsDOMEventTargetHelper::DispatchDOMEvent(aEvent,
aDOMEvent,
aPresContext,
aEventStatus);
}
nsEventListenerManager *
nsDOMDeviceStorage::GetListenerManager(bool aMayCreate)
{
return nsDOMEventTargetHelper::GetListenerManager(aMayCreate);
}
nsIScriptContext *
nsDOMDeviceStorage::GetContextForEventHandlers(nsresult *aRv)
{
return nsDOMEventTargetHelper::GetContextForEventHandlers(aRv);
}
JSContext *
nsDOMDeviceStorage::GetJSContextForEventHandlers()
{
return nsDOMEventTargetHelper::GetJSContextForEventHandlers();
}
NS_IMPL_EVENT_HANDLER(nsDOMDeviceStorage, change)

View File

@ -6,28 +6,25 @@
#define nsDeviceStorage_h
class nsPIDOMWindow;
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/PBrowserChild.h"
#include "mozilla/dom/devicestorage/PDeviceStorageRequestChild.h"
#include "PCOMContentPermissionRequestChild.h"
#include "DOMRequest.h"
#include "PCOMContentPermissionRequestChild.h"
#include "mozilla/Attributes.h"
#include "mozilla/dom/PContentPermissionRequestChild.h"
#include "nsAutoPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsDOMClassInfoID.h"
#include "nsIClassInfo.h"
#include "nsIContentPermissionPrompt.h"
#include "nsIDOMDeviceStorage.h"
#include "nsIDOMDeviceStorageCursor.h"
#include "nsIDOMWindow.h"
#include "nsIURI.h"
#include "nsInterfaceHashtable.h"
#include "nsString.h"
#include "nsWeakPtr.h"
#include "nsIDOMEventListener.h"
#include "nsIDOMEventTarget.h"
#include "nsIObserver.h"
#include "mozilla/Mutex.h"
#include "DeviceStorage.h"
#define POST_ERROR_EVENT_FILE_DOES_NOT_EXIST "File location doesn't exists"
@ -66,41 +63,6 @@ private:
void AppendRelativePath();
};
class nsDOMDeviceStorage MOZ_FINAL : public nsIDOMDeviceStorage
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMDEVICESTORAGE
nsDOMDeviceStorage();
nsresult Init(nsPIDOMWindow* aWindow, const nsAString &aType, const PRInt32 aIndex);
PRInt32 SetRootFileForType(const nsAString& aType, const PRInt32 aIndex);
static void CreateDeviceStoragesFor(nsPIDOMWindow* aWin, const nsAString &aType, nsIVariant** _retval);
private:
~nsDOMDeviceStorage();
nsresult GetInternal(const JS::Value & aName, JSContext* aCx, nsIDOMDOMRequest * *_retval, bool aEditable);
nsresult EnumerateInternal(const JS::Value & aName, const JS::Value & aOptions, JSContext* aCx, PRUint8 aArgc, bool aEditable, nsIDOMDeviceStorageCursor** aRetval);
PRInt32 mStorageType;
nsCOMPtr<nsIFile> mFile;
nsWeakPtr mOwner;
nsCOMPtr<nsIURI> mURI;
// nsIDOMDeviceStorage.type
enum {
DEVICE_STORAGE_TYPE_DEFAULT = 0,
DEVICE_STORAGE_TYPE_SHARED,
DEVICE_STORAGE_TYPE_EXTERNAL,
};
};
class ContinueCursorEvent MOZ_FINAL: public nsRunnable
{
public:

View File

@ -59,13 +59,13 @@ function createRandomBlob() {
}
function randomFilename(l) {
var set = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZ";
var result = "";
for (var i=0; i<l; i++) {
var r = Math.floor(set.length * Math.random());
result += set.substring(r, r + 1);
}
return result;
var set = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZ";
var result = "";
for (var i=0; i<l; i++) {
var r = Math.floor(set.length * Math.random());
result += set.substring(r, r + 1);
}
return result;
}
function reportErrorAndQuit(e) {

View File

@ -54,7 +54,7 @@ function deleteSuccess(e) {
dump(e.target.result + "\n")
var storage = navigator.getDeviceStorage("testing");
request = storage[0].get(e.target.result);
request = storage.get(e.target.result);
request.onsuccess = getAfterDeleteSuccess;
request.onerror = getAfterDeleteError;
@ -77,7 +77,7 @@ function getSuccess(e) {
gFileReader.onload = function(e) {
readerCallback(e);
request = storage[0].delete(name)
request = storage.delete(name)
request.onsuccess = deleteSuccess;
request.onerror = deleteError;
}
@ -102,7 +102,7 @@ function addSuccess(e) {
ok(e.target.result == gFileName, "File name should match");
var storage = navigator.getDeviceStorage("testing");
request = storage[0].get(gFileName);
request = storage.get(gFileName);
request.onsuccess = getSuccess;
request.onerror = getError;
@ -119,7 +119,7 @@ ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
var storage = navigator.getDeviceStorage("testing");
ok(storage, "Should have gotten a storage");
request = storage[0].addNamed(gDataBlob, "devicestorage/hi");
request = storage.addNamed(gDataBlob, "devicestorage/hi");
ok(request, "Should have a non-null request");
request.onsuccess = addSuccess;

View File

@ -25,7 +25,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=717103
devicestorage_setup();
function testingStorage() {
return navigator.getDeviceStorage("testing")[0];
return navigator.getDeviceStorage("testing");
}
var tests = [

View File

@ -41,7 +41,7 @@ function enumerateSuccess(e) {
ok(index > -1, "filename should be in the enumeration : " + e.target.result.name);
// clean up
var cleanup = storage[0].delete(prefix + "/" + filename);
var cleanup = storage.delete(prefix + "/" + filename);
cleanup.onsuccess = function(e) {} // todo - can i remove this?
e.target.continue();
@ -56,7 +56,7 @@ function addSuccess(e) {
addedSoFar = addedSoFar + 1;
if (addedSoFar == files.length) {
var cursor = storage[0].enumerate(prefix);
var cursor = storage.enumerate(prefix);
cursor.onsuccess = enumerateSuccess;
cursor.onerror = handleError;
}
@ -77,7 +77,7 @@ var addedSoFar = 0;
for (var i=0; i<files.length; i++) {
request = storage[0].addNamed(createRandomBlob(), prefix + '/' + files[i]);
request = storage.addNamed(createRandomBlob(), prefix + '/' + files[i]);
ok(request, "Should have a non-null request");
request.onsuccess = addSuccess;

View File

@ -30,7 +30,7 @@ function enumerateSuccess(e) {
function enumerateFailure(e) {
}
var cursor = navigator.getDeviceStorage("testing")[0].enumerate();
var cursor = navigator.getDeviceStorage("testing").enumerate();
cursor.onsuccess = enumerateSuccess;
cursor.onerror = enumerateFailure;

View File

@ -45,7 +45,7 @@ function enumerateSuccess(e) {
ok(index > -1, "filename should be in the enumeration : " + e.target.result.name);
// clean up
var cleanup = storage[0].delete(prefix + "/" + filename);
var cleanup = storage.delete(prefix + "/" + filename);
cleanup.onsuccess = function(e) {} // todo - can i remove this?
e.target.continue();
@ -60,7 +60,7 @@ function addSuccess(e) {
addedSoFar = addedSoFar + 1;
if (addedSoFar == files.length) {
var cursor = storage[0].enumerate();
var cursor = storage.enumerate();
cursor.onsuccess = enumerateSuccess;
cursor.onerror = handleError;
}
@ -81,7 +81,7 @@ var addedSoFar = 0;
for (var i=0; i<files.length; i++) {
request = storage[0].addNamed(createRandomBlob(), prefix + '/' + files[i]);
request = storage.addNamed(createRandomBlob(), prefix + '/' + files[i]);
ok(request, "Should have a non-null request");
request.onsuccess = addSuccess;

View File

@ -30,43 +30,43 @@ storage = navigator.getDeviceStorage("testing");
throws = false;
try {
var cursor = storage[0].enumerate();
var cursor = storage.enumerate();
} catch(e) {throws = true}
ok(!throws, "enumerate no parameter");
throws = false;
try {
var cursor = storage[0].enumerate("string");
var cursor = storage.enumerate("string");
} catch(e) {throws = true}
ok(!throws, "enumerate one string parameter");
throws = false;
try {
var cursor = storage[0].enumerate("string", "string2");
var cursor = storage.enumerate("string", "string2");
} catch(e) {throws = true}
ok(throws, "enumerate two string parameter");
throws = false;
try {
var cursor = storage[0].enumerate("string", {"since": 1});
var cursor = storage.enumerate("string", {"since": 1});
} catch(e) {throws = true}
ok(!throws, "enumerate a string and object parameter");
throws = false;
try {
var cursor = storage[0].enumerate({"path": "a"});
var cursor = storage.enumerate({"path": "a"});
} catch(e) {throws = true}
ok(!throws, "enumerate object parameter with path");
throws = false;
try {
var cursor = storage[0].enumerate({}, "string");
var cursor = storage.enumerate({}, "string");
} catch(e) {throws = true}
ok(throws, "enumerate object then a string");
throws = false;
try {
var cursor = storage[0].enumerate({"path": "a", "since": 0});
var cursor = storage.enumerate({"path": "a", "since": 0});
} catch(e) {throws = true}
ok(!throws, "enumerate object parameter with path");

View File

@ -45,7 +45,7 @@ function verifyAndDelete(prefix, files, e) {
// clean up
var storage = navigator.getDeviceStorage("testing");
var cleanup = storage[0].delete(prefix + "/" + filename);
var cleanup = storage.delete(prefix + "/" + filename);
cleanup.onsuccess = function(e) {}
}
@ -88,7 +88,7 @@ function enumerateNew() {
ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
// 836031600 is a long time ago
var cursor = storage[0].enumerate(prefix, {"since": new Date(836031600)});
var cursor = storage.enumerate(prefix, {"since": new Date(836031600)});
cursor.onsuccess = function(e) {
verifyAndDelete(prefix, newFiles, e);
if (e.target.result) {

View File

@ -46,7 +46,7 @@ function addOverwritingError(e) {
ok(true, "Adding to the same location should fail");
var storage = navigator.getDeviceStorage("testing");
request = storage[0].delete(filename)
request = storage.delete(filename)
request.onsuccess = deleteSuccess;
request.onerror = deleteError;
}
@ -57,7 +57,7 @@ function addSuccess(e) {
var storage = navigator.getDeviceStorage("testing");
ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
request = storage[0].addNamed(createRandomBlob(), filename);
request = storage.addNamed(createRandomBlob(), filename);
ok(request, "Should have a non-null request");
request.onsuccess = addOverwritingSuccess;
@ -67,7 +67,7 @@ function addSuccess(e) {
function addError(e) {
// test file is already exists. clean it up and try again..
var storage = navigator.getDeviceStorage("testing");
request = storage[0].delete(filename)
request = storage.delete(filename)
request.onsuccess = runtest;
}
@ -75,7 +75,7 @@ function runtest() {
var storage = navigator.getDeviceStorage("testing");
ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
request = storage[0].addNamed(createRandomBlob(), filename);
request = storage.addNamed(createRandomBlob(), filename);
ok(request, "Should have a non-null request");
request.onsuccess = addSuccess;

View File

@ -41,7 +41,7 @@ ok(!storage, "kilimanjaro - Should not have this type of storage");
storage = navigator.getDeviceStorage("testing");
ok(storage, "testing - Should have getDeviceStorage");
var cursor = storage[0].enumerate();
var cursor = storage.enumerate();
ok(cursor, "Should have a non-null cursor");
devicestorage_cleanup();

View File

@ -516,10 +516,9 @@ LockedFile::GetLocation(JSContext* aCx,
if (mLocation == LL_MAXUINT) {
*aLocation = JSVAL_NULL;
}
else if (!JS_NewNumberValue(aCx, double(mLocation), aLocation)) {
return NS_ERROR_FAILURE;
else {
*aLocation = JS_NumberValue(double(mLocation));
}
return NS_OK;
}

View File

@ -32,17 +32,7 @@ MetadataHelper::GetSuccessResult(JSContext* aCx,
NS_ENSURE_TRUE(obj, NS_ERROR_OUT_OF_MEMORY);
if (mParams->SizeRequested()) {
jsval val;
if (mParams->Size() <= JSVAL_INT_MAX) {
val = INT_TO_JSVAL(mParams->Size());
}
else {
double size = mParams->Size();
if (!JS_NewNumberValue(aCx, size, &val)) {
return NS_ERROR_FAILURE;
}
}
jsval val = JS_NumberValue(mParams->Size());
if (!JS_DefineProperty(aCx, obj, "size", val, nullptr, nullptr,
JSPROP_ENUMERATE)) {

View File

@ -12,6 +12,7 @@ include $(DEPTH)/config/autoconf.mk
MOCHITEST_FILES = \
dummy_worker.js \
helpers.js \
test_append_read_data.html \
test_getFileId.html \
@ -27,6 +28,7 @@ MOCHITEST_FILES = \
test_success_events_after_abort.html \
test_truncate.html \
test_write_read_data.html \
test_workers.html \
test_archivereader.html \
$(NULL)

View File

@ -0,0 +1,8 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
onmessage = function(event) {
throw("Shouldn't be called!");
}

View File

@ -0,0 +1,61 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>File Handle Test</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript;version=1.7">
function testSteps()
{
var testBuffer = getRandomBuffer(100000);
for each (let fileStorage in fileStorages) {
let request = getFileHandle(fileStorage.key, "test.txt");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
let fileHandle = event.target.result;
fileHandle.onerror = errorHandler;
let lockedFile = fileHandle.open("readwrite");
request = lockedFile.write(testBuffer);
request.onsuccess = grabEventAndContinueHandler;
event = yield;
request = fileHandle.getFile();
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let file = event.target.result;
var worker = new Worker("dummy_worker.js");
try {
worker.postMessage(file);
ok(false, "Should have thrown!");
}
catch (e) {
ok(e instanceof DOMException, "Got exception.");
is(e.name, "DataCloneError", "Good error.");
is(e.code, DOMException.DATA_CLONE_ERR, "Good error code.")
}
worker.terminate();
}
finishTest();
yield;
}
</script>
<script type="text/javascript;version=1.7" src="helpers.js"></script>
</head>
<body onload="runTest();"></body>
</html>

View File

@ -749,7 +749,7 @@ IDBCursor::Advance(PRInt64 aCount)
}
Key key;
return ContinueInternal(key, aCount);
return ContinueInternal(key, PRInt32(aCount));
}
void
@ -876,9 +876,26 @@ ContinueHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
return Success_NotSent;
}
if (!mCloneReadInfo.mFileInfos.IsEmpty()) {
NS_WARNING("No support for transferring blobs across processes yet!");
return Error;
InfallibleTArray<PBlobParent*> blobsParent;
if (NS_SUCCEEDED(aResultCode)) {
IDBDatabase* database = mTransaction->Database();
NS_ASSERTION(database, "This should never be null!");
ContentParent* contentParent = database->GetContentParent();
NS_ASSERTION(contentParent, "This should never be null!");
FileManager* fileManager = database->Manager();
NS_ASSERTION(fileManager, "This should never be null!");
const nsTArray<StructuredCloneFile>& files = mCloneReadInfo.mFiles;
aResultCode =
IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files,
blobsParent);
if (NS_FAILED(aResultCode)) {
NS_WARNING("ConvertBlobsToActors failed!");
}
}
ResponseValue response;
@ -890,6 +907,7 @@ ContinueHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
continueResponse.key() = mKey;
continueResponse.objectKey() = mObjectKey;
continueResponse.cloneInfo() = mCloneReadInfo;
continueResponse.blobsParent().SwapElements(blobsParent);
response = continueResponse;
}
@ -925,6 +943,8 @@ ContinueHelper::UnpackResponseFromParentProcess(
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
IDBObjectStore::ConvertActorsToBlobs(response.blobsChild(),
mCloneReadInfo.mFiles);
return NS_OK;
}

View File

@ -10,6 +10,7 @@
#include "mozilla/Mutex.h"
#include "mozilla/storage.h"
#include "mozilla/dom/ContentParent.h"
#include "nsDOMClassInfo.h"
#include "nsDOMLists.h"
#include "nsJSUtils.h"
@ -33,6 +34,7 @@
#include "ipc/IndexedDBChild.h"
USING_INDEXEDDB_NAMESPACE
using mozilla::dom::ContentParent;
namespace {
@ -170,7 +172,8 @@ already_AddRefed<IDBDatabase>
IDBDatabase::Create(IDBWrapperCache* aOwnerCache,
already_AddRefed<DatabaseInfo> aDatabaseInfo,
const nsACString& aASCIIOrigin,
FileManager* aFileManager)
FileManager* aFileManager,
mozilla::dom::ContentParent* aContentParent)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(!aASCIIOrigin.IsEmpty(), "Empty origin!");
@ -191,6 +194,7 @@ IDBDatabase::Create(IDBWrapperCache* aOwnerCache,
databaseInfo.swap(db->mDatabaseInfo);
db->mASCIIOrigin = aASCIIOrigin;
db->mFileManager = aFileManager;
db->mContentParent = aContentParent;
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
NS_ASSERTION(mgr, "This should never be null!");
@ -207,6 +211,7 @@ IDBDatabase::IDBDatabase()
: mDatabaseId(0),
mActorChild(nullptr),
mActorParent(nullptr),
mContentParent(nullptr),
mInvalidated(0),
mRegistered(false),
mClosed(false),

View File

@ -19,6 +19,12 @@
class nsIScriptContext;
class nsPIDOMWindow;
namespace mozilla {
namespace dom {
class ContentParent;
}
}
BEGIN_INDEXEDDB_NAMESPACE
class AsyncConnectionHelper;
@ -50,7 +56,8 @@ public:
Create(IDBWrapperCache* aOwnerCache,
already_AddRefed<DatabaseInfo> aDatabaseInfo,
const nsACString& aASCIIOrigin,
FileManager* aFileManager);
FileManager* aFileManager,
mozilla::dom::ContentParent* aContentParent);
// nsIDOMEventTarget
virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor);
@ -135,6 +142,12 @@ public:
return mActorChild;
}
mozilla::dom::ContentParent*
GetContentParent() const
{
return mContentParent;
}
nsresult
CreateObjectStoreInternal(IDBTransaction* aTransaction,
const ObjectStoreInfoGuts& aInfo,
@ -165,6 +178,8 @@ private:
IndexedDBDatabaseChild* mActorChild;
IndexedDBDatabaseParent* mActorParent;
mozilla::dom::ContentParent* mContentParent;
PRInt32 mInvalidated;
bool mRegistered;
bool mClosed;

View File

@ -119,8 +119,8 @@ IDBVersionChangeEvent::GetNewVersion(JSContext* aCx,
if (!mNewVersion) {
*aNewVersion = JSVAL_NULL;
}
else if (!JS_NewNumberValue(aCx, double(mNewVersion), aNewVersion)) {
return NS_ERROR_FAILURE;
else {
*aNewVersion = JS_NumberValue(double(mNewVersion));
}
return NS_OK;

View File

@ -7,7 +7,6 @@
#include "base/basictypes.h"
#include "IDBFactory.h"
#include "nsIFile.h"
#include "nsIJSContextStack.h"
#include "nsIPrincipal.h"
@ -16,6 +15,7 @@
#include "nsIXPCScriptable.h"
#include "jsdbgapi.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/PBrowserChild.h"
#include "mozilla/dom/TabChild.h"
@ -46,6 +46,7 @@
USING_INDEXEDDB_NAMESPACE
using mozilla::dom::ContentChild;
using mozilla::dom::ContentParent;
using mozilla::dom::TabChild;
namespace {
@ -63,7 +64,7 @@ struct ObjectStoreInfoMap
IDBFactory::IDBFactory()
: mOwningObject(nullptr), mActorChild(nullptr), mActorParent(nullptr),
mRootedOwningObject(false)
mContentParent(nullptr), mRootedOwningObject(false)
{
}
@ -84,6 +85,7 @@ IDBFactory::~IDBFactory()
nsresult
IDBFactory::Create(nsPIDOMWindow* aWindow,
const nsACString& aASCIIOrigin,
ContentParent* aContentParent,
IDBFactory** aFactory)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
@ -118,6 +120,7 @@ IDBFactory::Create(nsPIDOMWindow* aWindow,
nsRefPtr<IDBFactory> factory = new IDBFactory();
factory->mASCIIOrigin = origin;
factory->mWindow = aWindow;
factory->mContentParent = aContentParent;
if (!IndexedDatabaseManager::IsMainProcess()) {
TabChild* tabChild = GetTabChildFrom(aWindow);
@ -145,6 +148,7 @@ IDBFactory::Create(nsPIDOMWindow* aWindow,
nsresult
IDBFactory::Create(JSContext* aCx,
JSObject* aOwningObject,
ContentParent* aContentParent,
IDBFactory** aFactory)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
@ -162,6 +166,7 @@ IDBFactory::Create(JSContext* aCx,
nsRefPtr<IDBFactory> factory = new IDBFactory();
factory->mASCIIOrigin = origin;
factory->mOwningObject = aOwningObject;
factory->mContentParent = aContentParent;
if (!IndexedDatabaseManager::IsMainProcess()) {
ContentChild* contentChild = ContentChild::GetSingleton();
@ -180,11 +185,13 @@ IDBFactory::Create(JSContext* aCx,
// static
nsresult
IDBFactory::Create(IDBFactory** aFactory)
IDBFactory::Create(ContentParent* aContentParent,
IDBFactory** aFactory)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
NS_ASSERTION(nsContentUtils::IsCallerChrome(), "Only for chrome!");
NS_ASSERTION(aContentParent, "Null ContentParent!");
#ifdef DEBUG
{
@ -243,7 +250,7 @@ IDBFactory::Create(IDBFactory** aFactory)
}
nsRefPtr<IDBFactory> factory;
rv = Create(cx, global, getter_AddRefs(factory));
rv = Create(cx, global, aContentParent, getter_AddRefs(factory));
NS_ENSURE_SUCCESS(rv, rv);
NS_HOLD_JS_OBJECTS(factory, IDBFactory);
@ -529,10 +536,10 @@ IDBFactory::OpenCommon(const nsAString& aName,
nsresult rv;
if (IndexedDatabaseManager::IsMainProcess()) {
if (IndexedDatabaseManager::IsMainProcess()) {
nsRefPtr<OpenDatabaseHelper> openHelper =
new OpenDatabaseHelper(request, aName, mASCIIOrigin, aVersion, aDeleting,
privilege);
mContentParent, privilege);
rv = openHelper->Init();
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
@ -628,4 +635,4 @@ IDBFactory::Cmp(const jsval& aFirst,
*_retval = Key::CompareKeys(first, second);
return NS_OK;
}
}

View File

@ -17,6 +17,12 @@
class nsIAtom;
class nsPIDOMWindow;
namespace mozilla {
namespace dom {
class ContentParent;
}
}
BEGIN_INDEXEDDB_NAMESPACE
struct DatabaseInfo;
@ -29,6 +35,7 @@ struct ObjectStoreInfo;
class IDBFactory MOZ_FINAL : public nsIIDBFactory
{
typedef mozilla::dom::ContentParent ContentParent;
typedef nsTArray<nsRefPtr<ObjectStoreInfo> > ObjectStoreInfoArray;
public:
@ -39,14 +46,17 @@ public:
// Called when using IndexedDB from a window in a different process.
static nsresult Create(nsPIDOMWindow* aWindow,
const nsACString& aASCIIOrigin,
ContentParent* aContentParent,
IDBFactory** aFactory);
// Called when using IndexedDB from a window in the current process.
static nsresult Create(nsPIDOMWindow* aWindow,
ContentParent* aContentParent,
nsIIDBFactory** aFactory)
{
nsRefPtr<IDBFactory> factory;
nsresult rv = Create(aWindow, EmptyCString(), getter_AddRefs(factory));
nsresult rv =
Create(aWindow, EmptyCString(), aContentParent, getter_AddRefs(factory));
NS_ENSURE_SUCCESS(rv, rv);
factory.forget(aFactory);
@ -57,11 +67,13 @@ public:
// process.
static nsresult Create(JSContext* aCx,
JSObject* aOwningObject,
ContentParent* aContentParent,
IDBFactory** aFactory);
// Called when using IndexedDB from a JS component or a JSM in a different
// process.
static nsresult Create(IDBFactory** aFactory);
static nsresult Create(ContentParent* aContentParent,
IDBFactory** aFactory);
static already_AddRefed<mozIStorageConnection>
GetConnection(const nsAString& aDatabaseFilePath);
@ -118,6 +130,8 @@ private:
IndexedDBChild* mActorChild;
IndexedDBParent* mActorParent;
mozilla::dom::ContentParent* mContentParent;
bool mRootedOwningObject;
};

View File

@ -11,6 +11,9 @@
#include "nsIIDBKeyRange.h"
#include "nsIJSContextStack.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/ipc/Blob.h"
#include "nsContentUtils.h"
#include "nsDOMClassInfoID.h"
#include "nsEventDispatcher.h"
@ -32,6 +35,7 @@
#include "IndexedDatabaseInlines.h"
USING_INDEXEDDB_NAMESPACE
using namespace mozilla::dom;
using namespace mozilla::dom::indexedDB::ipc;
namespace {
@ -634,6 +638,7 @@ IDBIndex::OpenCursorFromChildProcess(
const Key& aKey,
const Key& aObjectKey,
const SerializedStructuredCloneReadInfo& aCloneInfo,
nsTArray<StructuredCloneFile>& aBlobs,
IDBCursor** _retval)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
@ -651,6 +656,8 @@ IDBIndex::OpenCursorFromChildProcess(
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
cloneInfo.mFiles.SwapElements(aBlobs);
nsRefPtr<IDBCursor> cursor =
IDBCursor::Create(aRequest, mObjectStore->Transaction(), this, direction,
Key(), EmptyCString(), EmptyCString(), aKey, aObjectKey,
@ -1236,9 +1243,26 @@ GetHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
return Success_NotSent;
}
if (!mCloneReadInfo.mFileInfos.IsEmpty()) {
NS_WARNING("No support for transferring blobs across processes yet!");
return Error;
InfallibleTArray<PBlobParent*> blobsParent;
if (NS_SUCCEEDED(aResultCode)) {
IDBDatabase* database = mIndex->ObjectStore()->Transaction()->Database();
NS_ASSERTION(database, "This should never be null!");
ContentParent* contentParent = database->GetContentParent();
NS_ASSERTION(contentParent, "This should never be null!");
FileManager* fileManager = database->Manager();
NS_ASSERTION(fileManager, "This should never be null!");
const nsTArray<StructuredCloneFile>& files = mCloneReadInfo.mFiles;
aResultCode =
IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files,
blobsParent);
if (NS_FAILED(aResultCode)) {
NS_WARNING("ConvertBlobActors failed!");
}
}
ResponseValue response;
@ -1246,9 +1270,9 @@ GetHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
response = aResultCode;
}
else {
SerializedStructuredCloneReadInfo readInfo;
readInfo = mCloneReadInfo;
GetResponse getResponse = readInfo;
GetResponse getResponse;
getResponse.cloneInfo() = mCloneReadInfo;
getResponse.blobsParent().SwapElements(blobsParent);
response = getResponse;
}
@ -1265,8 +1289,8 @@ GetHelper::UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
NS_ASSERTION(aResponseValue.type() == ResponseValue::TGetResponse,
"Bad response type!");
const SerializedStructuredCloneReadInfo& cloneInfo =
aResponseValue.get_GetResponse().cloneInfo();
const GetResponse& getResponse = aResponseValue.get_GetResponse();
const SerializedStructuredCloneReadInfo& cloneInfo = getResponse.cloneInfo();
NS_ASSERTION((!cloneInfo.dataLength && !cloneInfo.data) ||
(cloneInfo.dataLength && cloneInfo.data),
@ -1277,6 +1301,8 @@ GetHelper::UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
IDBObjectStore::ConvertActorsToBlobs(getResponse.blobsChild(),
mCloneReadInfo.mFiles);
return NS_OK;
}
@ -1567,10 +1593,50 @@ GetAllHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
return Success_NotSent;
}
for (PRUint32 index = 0; index < mCloneReadInfos.Length(); index++) {
if (!mCloneReadInfos[index].mFileInfos.IsEmpty()) {
NS_WARNING("No support for transferring blobs across processes yet!");
return Error;
GetAllResponse getAllResponse;
if (NS_SUCCEEDED(aResultCode) && !mCloneReadInfos.IsEmpty()) {
IDBDatabase* database = mIndex->ObjectStore()->Transaction()->Database();
NS_ASSERTION(database, "This should never be null!");
ContentParent* contentParent = database->GetContentParent();
NS_ASSERTION(contentParent, "This should never be null!");
FileManager* fileManager = database->Manager();
NS_ASSERTION(fileManager, "This should never be null!");
PRUint32 length = mCloneReadInfos.Length();
InfallibleTArray<SerializedStructuredCloneReadInfo>& infos =
getAllResponse.cloneInfos();
infos.SetCapacity(length);
InfallibleTArray<BlobArray>& blobArrays = getAllResponse.blobs();
blobArrays.SetCapacity(length);
for (PRUint32 index = 0;
NS_SUCCEEDED(aResultCode) && index < length;
index++) {
const StructuredCloneReadInfo& clone = mCloneReadInfos[index];
// Append the structured clone data.
SerializedStructuredCloneReadInfo* info = infos.AppendElement();
*info = clone;
const nsTArray<StructuredCloneFile>& files = clone.mFiles;
// Now take care of the files.
BlobArray* blobArray = blobArrays.AppendElement();
InfallibleTArray<PBlobParent*>& blobs = blobArray->blobsParent();
aResultCode =
IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files,
blobs);
if (NS_FAILED(aResultCode)) {
NS_WARNING("ConvertBlobsToActors failed!");
break;
}
}
}
@ -1579,18 +1645,6 @@ GetAllHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
response = aResultCode;
}
else {
GetAllResponse getAllResponse;
InfallibleTArray<SerializedStructuredCloneReadInfo>& infos =
getAllResponse.cloneInfos();
infos.SetCapacity(mCloneReadInfos.Length());
for (PRUint32 index = 0; index < mCloneReadInfos.Length(); index++) {
SerializedStructuredCloneReadInfo* info = infos.AppendElement();
*info = mCloneReadInfos[index];
}
response = getAllResponse;
}
@ -1608,19 +1662,24 @@ GetAllHelper::UnpackResponseFromParentProcess(
NS_ASSERTION(aResponseValue.type() == ResponseValue::TGetAllResponse,
"Bad response type!");
const GetAllResponse& getAllResponse = aResponseValue.get_GetAllResponse();
const InfallibleTArray<SerializedStructuredCloneReadInfo>& cloneInfos =
aResponseValue.get_GetAllResponse().cloneInfos();
getAllResponse.cloneInfos();
const InfallibleTArray<BlobArray>& blobArrays = getAllResponse.blobs();
mCloneReadInfos.SetCapacity(cloneInfos.Length());
for (PRUint32 index = 0; index < cloneInfos.Length(); index++) {
const SerializedStructuredCloneReadInfo srcInfo = cloneInfos[index];
const InfallibleTArray<PBlobChild*> blobs = blobArrays[index].blobsChild();
StructuredCloneReadInfo* destInfo = mCloneReadInfos.AppendElement();
if (!destInfo->SetFromSerialized(srcInfo)) {
NS_WARNING("Failed to copy clone buffer!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
IDBObjectStore::ConvertActorsToBlobs(blobs, destInfo->mFiles);
}
return NS_OK;
@ -2199,13 +2258,30 @@ OpenCursorHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
return Success_NotSent;
}
if (!mCloneReadInfo.mFileInfos.IsEmpty()) {
NS_WARNING("No support for transferring blobs across processes yet!");
return Error;
}
NS_ASSERTION(!mCursor, "Shouldn't have this yet!");
InfallibleTArray<PBlobParent*> blobsParent;
if (NS_SUCCEEDED(aResultCode)) {
IDBDatabase* database = mIndex->ObjectStore()->Transaction()->Database();
NS_ASSERTION(database, "This should never be null!");
ContentParent* contentParent = database->GetContentParent();
NS_ASSERTION(contentParent, "This should never be null!");
FileManager* fileManager = database->Manager();
NS_ASSERTION(fileManager, "This should never be null!");
const nsTArray<StructuredCloneFile>& files = mCloneReadInfo.mFiles;
aResultCode =
IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files,
blobsParent);
if (NS_FAILED(aResultCode)) {
NS_WARNING("ConvertBlobsToActors failed!");
}
}
if (NS_SUCCEEDED(aResultCode)) {
nsresult rv = EnsureCursor();
if (NS_FAILED(rv)) {
@ -2241,6 +2317,7 @@ OpenCursorHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
params.key() = mKey;
params.objectKey() = mObjectKey;
params.optionalCloneInfo() = mSerializedCloneReadInfo;
params.blobsParent().SwapElements(blobsParent);
IndexedDBCursorParent* cursorActor = new IndexedDBCursorParent(mCursor);
@ -2324,11 +2401,7 @@ nsresult
CountHelper::GetSuccessResult(JSContext* aCx,
jsval* aVal)
{
if (!JS_NewNumberValue(aCx, static_cast<double>(mCount), aVal)) {
NS_WARNING("Failed to make number value!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
*aVal = JS_NumberValue(static_cast<double>(mCount));
return NS_OK;
}

View File

@ -145,6 +145,7 @@ public:
const Key& aKey,
const Key& aObjectKey,
const SerializedStructuredCloneReadInfo& aCloneInfo,
nsTArray<StructuredCloneFile>& aBlobs,
IDBCursor** _retval);
private:

View File

@ -12,7 +12,10 @@
#include "nsIOutputStream.h"
#include "jsfriendapi.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/StructuredCloneTags.h"
#include "mozilla/dom/ipc/Blob.h"
#include "mozilla/storage.h"
#include "nsContentUtils.h"
#include "nsDOMClassInfo.h"
@ -45,6 +48,7 @@
#define FILE_COPY_BUFFER_SIZE 32768
USING_INDEXEDDB_NAMESPACE
using namespace mozilla::dom;
using namespace mozilla::dom::indexedDB::ipc;
namespace {
@ -881,7 +885,8 @@ IDBObjectStore::GetStructuredCloneReadInfoFromStatement(
nsRefPtr<FileInfo> fileInfo = fileManager->GetFileInfo(id);
NS_ASSERTION(fileInfo, "Null file info!");
aInfo.mFileInfos.AppendElement(fileInfo);
StructuredCloneFile* file = aInfo.mFiles.AppendElement();
file->mFileInfo.swap(fileInfo);
}
}
@ -954,9 +959,9 @@ static inline PRUint32
SwapBytes(PRUint32 u)
{
#ifdef IS_BIG_ENDIAN
return ((u & 0x000000ffU) << 24) |
((u & 0x0000ff00U) << 8) |
((u & 0x00ff0000U) >> 8) |
return ((u & 0x000000ffU) << 24) |
((u & 0x0000ff00U) << 8) |
((u & 0x00ff0000U) >> 8) |
((u & 0xff000000U) >> 24);
#else
return u;
@ -1005,6 +1010,7 @@ StructuredCloneReadString(JSStructuredCloneReader* aReader,
return true;
}
// static
JSObject*
IDBObjectStore::StructuredCloneReadCallback(JSContext* aCx,
JSStructuredCloneReader* aReader,
@ -1017,12 +1023,15 @@ IDBObjectStore::StructuredCloneReadCallback(JSContext* aCx,
StructuredCloneReadInfo* cloneReadInfo =
reinterpret_cast<StructuredCloneReadInfo*>(aClosure);
if (aData >= cloneReadInfo->mFileInfos.Length()) {
if (aData >= cloneReadInfo->mFiles.Length()) {
NS_ERROR("Bad blob index!");
return nullptr;
}
nsRefPtr<FileInfo> fileInfo = cloneReadInfo->mFileInfos[aData];
nsresult rv;
StructuredCloneFile& file = cloneReadInfo->mFiles[aData];
nsRefPtr<FileInfo>& fileInfo = file.mFileInfo;
IDBDatabase* database = cloneReadInfo->mDatabase;
if (aTag == SCTAG_DOM_FILEHANDLE) {
@ -1042,7 +1051,7 @@ IDBObjectStore::StructuredCloneReadCallback(JSContext* aCx,
convName, convType, fileInfo.forget());
jsval wrappedFileHandle;
nsresult rv =
rv =
nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx),
static_cast<nsIDOMFileHandle*>(fileHandle),
&NS_GET_IID(nsIDOMFileHandle),
@ -1055,21 +1064,6 @@ IDBObjectStore::StructuredCloneReadCallback(JSContext* aCx,
return JSVAL_TO_OBJECT(wrappedFileHandle);
}
FileManager* fileManager = database->Manager();
nsCOMPtr<nsIFile> directory = fileManager->GetDirectory();
if (!directory) {
NS_WARNING("Failed to get directory!");
return nullptr;
}
nsCOMPtr<nsIFile> nativeFile =
fileManager->GetFileForId(directory, fileInfo->Id());
if (!nativeFile) {
NS_WARNING("Failed to get file!");
return nullptr;
}
PRUint64 size;
if (!JS_ReadBytes(aReader, &size, sizeof(PRUint64))) {
NS_WARNING("Failed to read size!");
@ -1083,13 +1077,36 @@ IDBObjectStore::StructuredCloneReadCallback(JSContext* aCx,
}
NS_ConvertUTF8toUTF16 convType(type);
nsCOMPtr<nsIFile> nativeFile;
if (!file.mFile) {
FileManager* fileManager = database->Manager();
NS_ASSERTION(fileManager, "This should never be null!");
nsCOMPtr<nsIFile> directory = fileManager->GetDirectory();
if (!directory) {
NS_WARNING("Failed to get directory!");
return nullptr;
}
nativeFile = fileManager->GetFileForId(directory, fileInfo->Id());
if (!nativeFile) {
NS_WARNING("Failed to get file!");
return nullptr;
}
}
if (aTag == SCTAG_DOM_BLOB) {
nsCOMPtr<nsIDOMBlob> blob = new nsDOMFileFile(convType, size,
nativeFile, fileInfo);
nsCOMPtr<nsIDOMBlob> domBlob;
if (file.mFile) {
domBlob = file.mFile;
}
else {
domBlob = new nsDOMFileFile(convType, size, nativeFile, fileInfo);
}
jsval wrappedBlob;
nsresult rv =
nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), blob,
rv =
nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), domBlob,
&NS_GET_IID(nsIDOMBlob), &wrappedBlob);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to wrap native!");
@ -1099,18 +1116,27 @@ IDBObjectStore::StructuredCloneReadCallback(JSContext* aCx,
return JSVAL_TO_OBJECT(wrappedBlob);
}
NS_ASSERTION(aTag == SCTAG_DOM_FILE, "Huh?!");
nsCString name;
if (!StructuredCloneReadString(aReader, name)) {
return nullptr;
}
NS_ConvertUTF8toUTF16 convName(name);
nsCOMPtr<nsIDOMFile> file = new nsDOMFileFile(convName, convType, size,
nativeFile, fileInfo);
nsCOMPtr<nsIDOMFile> domFile;
if (file.mFile) {
domFile = do_QueryInterface(file.mFile);
NS_ASSERTION(domFile, "This should never fail!");
}
else {
domFile = new nsDOMFileFile(convName, convType, size, nativeFile,
fileInfo);
}
jsval wrappedFile;
nsresult rv =
nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), file,
rv =
nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), domFile,
&NS_GET_IID(nsIDOMFile), &wrappedFile);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to wrap native!");
@ -1130,6 +1156,7 @@ IDBObjectStore::StructuredCloneReadCallback(JSContext* aCx,
return nullptr;
}
// static
JSBool
IDBObjectStore::StructuredCloneWriteCallback(JSContext* aCx,
JSStructuredCloneWriter* aWriter,
@ -1160,29 +1187,28 @@ IDBObjectStore::StructuredCloneWriteCallback(JSContext* aCx,
nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(supports);
if (blob) {
// Check if it is a blob created from this db or the blob was already
// stored in this db
nsRefPtr<FileInfo> fileInfo = transaction->GetFileInfo(blob);
nsCOMPtr<nsIInputStream> inputStream;
if (!fileInfo) {
// Check if it is a blob created from this db or the blob was already
// stored in this db
nsRefPtr<FileInfo> fileInfo = transaction->GetFileInfo(blob);
if (!fileInfo && fileManager) {
fileInfo = blob->GetFileInfo(fileManager);
}
if (!fileInfo) {
fileInfo = fileManager->GetNewFileInfo();
if (!fileInfo) {
NS_WARNING("Failed to get new file info!");
return false;
}
fileInfo = fileManager->GetNewFileInfo();
if (!fileInfo) {
NS_WARNING("Failed to get new file info!");
return false;
}
if (NS_FAILED(blob->GetInternalStream(getter_AddRefs(inputStream)))) {
NS_WARNING("Failed to get internal steam!");
return false;
}
if (NS_FAILED(blob->GetInternalStream(getter_AddRefs(inputStream)))) {
NS_WARNING("Failed to get internal steam!");
return false;
}
transaction->AddFileInfo(blob, fileInfo);
transaction->AddFileInfo(blob, fileInfo);
}
}
PRUint64 size;
@ -1204,8 +1230,8 @@ IDBObjectStore::StructuredCloneWriteCallback(JSContext* aCx,
if (!JS_WriteUint32Pair(aWriter, file ? SCTAG_DOM_FILE : SCTAG_DOM_BLOB,
cloneWriteInfo->mFiles.Length()) ||
!JS_WriteBytes(aWriter, &size, sizeof(PRUint64)) ||
!JS_WriteBytes(aWriter, &convTypeLength, sizeof(PRUint32)) ||
!JS_WriteBytes(aWriter, &size, sizeof(size)) ||
!JS_WriteBytes(aWriter, &convTypeLength, sizeof(convTypeLength)) ||
!JS_WriteBytes(aWriter, convType.get(), convType.Length())) {
return false;
}
@ -1219,7 +1245,7 @@ IDBObjectStore::StructuredCloneWriteCallback(JSContext* aCx,
NS_ConvertUTF16toUTF8 convName(name);
PRUint32 convNameLength = SwapBytes(convName.Length());
if (!JS_WriteBytes(aWriter, &convNameLength, sizeof(PRUint32)) ||
if (!JS_WriteBytes(aWriter, &convNameLength, sizeof(convNameLength)) ||
!JS_WriteBytes(aWriter, convName.get(), convName.Length())) {
return false;
}
@ -1285,6 +1311,7 @@ IDBObjectStore::StructuredCloneWriteCallback(JSContext* aCx,
return false;
}
// static
nsresult
IDBObjectStore::ConvertFileIdsToArray(const nsAString& aFileIds,
nsTArray<PRInt64>& aResult)
@ -1307,6 +1334,79 @@ IDBObjectStore::ConvertFileIdsToArray(const nsAString& aFileIds,
return NS_OK;
}
// static
void
IDBObjectStore::ConvertActorsToBlobs(
const InfallibleTArray<PBlobChild*>& aActors,
nsTArray<StructuredCloneFile>& aFiles)
{
NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aFiles.IsEmpty(), "Should be empty!");
if (!aActors.IsEmpty()) {
ContentChild* contentChild = ContentChild::GetSingleton();
NS_ASSERTION(contentChild, "This should never be null!");
PRUint32 length = aActors.Length();
aFiles.SetCapacity(length);
for (PRUint32 index = 0; index < length; index++) {
BlobChild* actor = static_cast<BlobChild*>(aActors[index]);
StructuredCloneFile* file = aFiles.AppendElement();
file->mFile = actor->GetBlob();
}
}
}
// static
nsresult
IDBObjectStore::ConvertBlobsToActors(
ContentParent* aContentParent,
FileManager* aFileManager,
const nsTArray<StructuredCloneFile>& aFiles,
InfallibleTArray<PBlobParent*>& aActors)
{
NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aContentParent, "Null contentParent!");
NS_ASSERTION(aFileManager, "Null file manager!");
if (!aFiles.IsEmpty()) {
nsCOMPtr<nsIFile> directory = aFileManager->GetDirectory();
if (!directory) {
NS_WARNING("Failed to get directory!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
PRUint32 fileCount = aFiles.Length();
aActors.SetCapacity(fileCount);
for (PRUint32 index = 0; index < fileCount; index++) {
const StructuredCloneFile& file = aFiles[index];
NS_ASSERTION(file.mFileInfo, "This should never be null!");
nsCOMPtr<nsIFile> nativeFile =
aFileManager->GetFileForId(directory, file.mFileInfo->Id());
if (!nativeFile) {
NS_WARNING("Failed to get file!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
nsCOMPtr<nsIDOMBlob> blob = new nsDOMFileFile(nativeFile);
BlobParent* actor =
aContentParent->GetOrCreateActorForBlob(blob);
NS_ASSERTION(actor, "This should never fail without aborting!");
aActors.AppendElement(actor);
}
}
return NS_OK;
}
IDBObjectStore::IDBObjectStore()
: mId(LL_MININT),
mKeyPath(0),
@ -1448,6 +1548,7 @@ IDBObjectStore::AddOrPutInternal(
const SerializedStructuredCloneWriteInfo& aCloneWriteInfo,
const Key& aKey,
const InfallibleTArray<IndexUpdateInfo>& aUpdateInfoArray,
const nsTArray<nsCOMPtr<nsIDOMBlob> >& aBlobs,
bool aOverwrite,
IDBRequest** _retval)
{
@ -1471,6 +1572,48 @@ IDBObjectStore::AddOrPutInternal(
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
if (!aBlobs.IsEmpty()) {
FileManager* fileManager = Transaction()->Database()->Manager();
NS_ASSERTION(fileManager, "Null file manager?!");
PRUint32 length = aBlobs.Length();
cloneWriteInfo.mFiles.SetCapacity(length);
for (PRUint32 index = 0; index < length; index++) {
const nsCOMPtr<nsIDOMBlob>& blob = aBlobs[index];
nsCOMPtr<nsIInputStream> inputStream;
nsRefPtr<FileInfo> fileInfo = Transaction()->GetFileInfo(blob);
if (!fileInfo) {
fileInfo = blob->GetFileInfo(fileManager);
if (!fileInfo) {
fileInfo = fileManager->GetNewFileInfo();
if (!fileInfo) {
NS_WARNING("Failed to get new file info!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
if (NS_FAILED(blob->GetInternalStream(getter_AddRefs(inputStream)))) {
NS_WARNING("Failed to get internal steam!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
// XXXbent This is where we should send a message back to the child to
// update the file id.
Transaction()->AddFileInfo(blob, fileInfo);
}
}
StructuredCloneFile* file = cloneWriteInfo.mFiles.AppendElement();
file->mFile = blob;
file->mFileInfo.swap(fileInfo);
file->mInputStream.swap(inputStream);
}
}
Key key(aKey);
nsTArray<IndexUpdateInfo> updateInfo(aUpdateInfoArray);
@ -1648,6 +1791,7 @@ IDBObjectStore::OpenCursorFromChildProcess(
size_t aDirection,
const Key& aKey,
const SerializedStructuredCloneReadInfo& aCloneInfo,
nsTArray<StructuredCloneFile>& aBlobs,
IDBCursor** _retval)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
@ -1665,6 +1809,8 @@ IDBObjectStore::OpenCursorFromChildProcess(
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
cloneInfo.mFiles.SwapElements(aBlobs);
nsRefPtr<IDBCursor> cursor =
IDBCursor::Create(aRequest, mTransaction, this, direction, Key(),
EmptyCString(), EmptyCString(), aKey, cloneInfo);
@ -2546,6 +2692,31 @@ AddHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams)
commonParams.key() = mKey;
commonParams.indexUpdateInfos().AppendElements(mIndexUpdateInfo);
const nsTArray<StructuredCloneFile>& files = mCloneWriteInfo.mFiles;
if (!files.IsEmpty()) {
PRUint32 fileCount = files.Length();
InfallibleTArray<PBlobChild*>& blobsChild = commonParams.blobsChild();
blobsChild.SetCapacity(fileCount);
ContentChild* contentChild = ContentChild::GetSingleton();
NS_ASSERTION(contentChild, "This should never be null!");
for (PRUint32 index = 0; index < fileCount; index++) {
const StructuredCloneFile& file = files[index];
NS_ASSERTION(file.mFile, "This should never be null!");
NS_ASSERTION(!file.mFileInfo, "This is not yet supported!");
BlobChild* actor =
contentChild->GetOrCreateActorForBlob(file.mFile);
NS_ASSERTION(actor, "This should never fail without aborting!");
blobsChild.AppendElement(actor);
}
}
if (mOverwrite) {
PutParams putParams;
putParams.commonParams() = commonParams;
@ -2690,9 +2861,26 @@ GetHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
return Success_NotSent;
}
if (!mCloneReadInfo.mFileInfos.IsEmpty()) {
NS_WARNING("No support for transferring blobs across processes yet!");
return Error;
InfallibleTArray<PBlobParent*> blobsParent;
if (NS_SUCCEEDED(aResultCode)) {
IDBDatabase* database = mObjectStore->Transaction()->Database();
NS_ASSERTION(database, "This should never be null!");
ContentParent* contentParent = database->GetContentParent();
NS_ASSERTION(contentParent, "This should never be null!");
FileManager* fileManager = database->Manager();
NS_ASSERTION(fileManager, "This should never be null!");
const nsTArray<StructuredCloneFile>& files = mCloneReadInfo.mFiles;
aResultCode =
IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files,
blobsParent);
if (NS_FAILED(aResultCode)) {
NS_WARNING("ConvertBlobsToActors failed!");
}
}
ResponseValue response;
@ -2700,9 +2888,9 @@ GetHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
response = aResultCode;
}
else {
SerializedStructuredCloneReadInfo readInfo;
readInfo = mCloneReadInfo;
GetResponse getResponse = readInfo;
GetResponse getResponse;
getResponse.cloneInfo() = mCloneReadInfo;
getResponse.blobsParent().SwapElements(blobsParent);
response = getResponse;
}
@ -2719,8 +2907,8 @@ GetHelper::UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
NS_ASSERTION(aResponseValue.type() == ResponseValue::TGetResponse,
"Bad response type!");
const SerializedStructuredCloneReadInfo& cloneInfo =
aResponseValue.get_GetResponse().cloneInfo();
const GetResponse& getResponse = aResponseValue.get_GetResponse();
const SerializedStructuredCloneReadInfo& cloneInfo = getResponse.cloneInfo();
NS_ASSERTION((!cloneInfo.dataLength && !cloneInfo.data) ||
(cloneInfo.dataLength && cloneInfo.data),
@ -2731,6 +2919,8 @@ GetHelper::UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
IDBObjectStore::ConvertActorsToBlobs(getResponse.blobsChild(),
mCloneReadInfo.mFiles);
return NS_OK;
}
@ -3099,13 +3289,30 @@ OpenCursorHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
return Success_NotSent;
}
if (!mCloneReadInfo.mFileInfos.IsEmpty()) {
NS_WARNING("No support for transferring blobs across processes yet!");
return Error;
}
NS_ASSERTION(!mCursor, "Shouldn't have this yet!");
InfallibleTArray<PBlobParent*> blobsParent;
if (NS_SUCCEEDED(aResultCode)) {
IDBDatabase* database = mObjectStore->Transaction()->Database();
NS_ASSERTION(database, "This should never be null!");
ContentParent* contentParent = database->GetContentParent();
NS_ASSERTION(contentParent, "This should never be null!");
FileManager* fileManager = database->Manager();
NS_ASSERTION(fileManager, "This should never be null!");
const nsTArray<StructuredCloneFile>& files = mCloneReadInfo.mFiles;
aResultCode =
IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files,
blobsParent);
if (NS_FAILED(aResultCode)) {
NS_WARNING("ConvertBlobsToActors failed!");
}
}
if (NS_SUCCEEDED(aResultCode)) {
nsresult rv = EnsureCursor();
if (NS_FAILED(rv)) {
@ -3141,6 +3348,7 @@ OpenCursorHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
params.direction() = mDirection;
params.key() = mKey;
params.cloneInfo() = mSerializedCloneReadInfo;
params.blobsParent().SwapElements(blobsParent);
IndexedDBCursorParent* cursorActor = new IndexedDBCursorParent(mCursor);
@ -3525,10 +3733,47 @@ GetAllHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
return Success_NotSent;
}
for (PRUint32 index = 0; index < mCloneReadInfos.Length(); index++) {
if (!mCloneReadInfos[index].mFileInfos.IsEmpty()) {
NS_WARNING("No support for transferring blobs across processes yet!");
return Error;
GetAllResponse getAllResponse;
if (NS_SUCCEEDED(aResultCode) && !mCloneReadInfos.IsEmpty()) {
IDBDatabase* database = mObjectStore->Transaction()->Database();
NS_ASSERTION(database, "This should never be null!");
ContentParent* contentParent = database->GetContentParent();
NS_ASSERTION(contentParent, "This should never be null!");
FileManager* fileManager = database->Manager();
NS_ASSERTION(fileManager, "This should never be null!");
PRUint32 length = mCloneReadInfos.Length();
InfallibleTArray<SerializedStructuredCloneReadInfo>& infos =
getAllResponse.cloneInfos();
infos.SetCapacity(length);
InfallibleTArray<BlobArray>& blobArrays = getAllResponse.blobs();
blobArrays.SetCapacity(length);
for (PRUint32 index = 0;
NS_SUCCEEDED(aResultCode) && index < length;
index++) {
// Append the structured clone data.
const StructuredCloneReadInfo& clone = mCloneReadInfos[index];
SerializedStructuredCloneReadInfo* info = infos.AppendElement();
*info = clone;
// Now take care of the files.
const nsTArray<StructuredCloneFile>& files = clone.mFiles;
BlobArray* blobArray = blobArrays.AppendElement();
InfallibleTArray<PBlobParent*>& blobs = blobArray->blobsParent();
aResultCode =
IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files,
blobs);
if (NS_FAILED(aResultCode)) {
NS_WARNING("ConvertBlobsToActors failed!");
break;
}
}
}
@ -3537,19 +3782,6 @@ GetAllHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
response = aResultCode;
}
else {
GetAllResponse getAllResponse;
InfallibleTArray<SerializedStructuredCloneReadInfo>& infos =
getAllResponse.cloneInfos();
infos.SetCapacity(mCloneReadInfos.Length());
for (PRUint32 index = 0; index < mCloneReadInfos.Length(); index++) {
SerializedStructuredCloneReadInfo* info = infos.AppendElement();
*info = mCloneReadInfos[index];
}
getAllResponse = infos;
response = getAllResponse;
}
@ -3567,19 +3799,24 @@ GetAllHelper::UnpackResponseFromParentProcess(
NS_ASSERTION(aResponseValue.type() == ResponseValue::TGetAllResponse,
"Bad response type!");
const GetAllResponse& getAllResponse = aResponseValue.get_GetAllResponse();
const InfallibleTArray<SerializedStructuredCloneReadInfo>& cloneInfos =
aResponseValue.get_GetAllResponse().cloneInfos();
getAllResponse.cloneInfos();
const InfallibleTArray<BlobArray>& blobArrays = getAllResponse.blobs();
mCloneReadInfos.SetCapacity(cloneInfos.Length());
for (PRUint32 index = 0; index < cloneInfos.Length(); index++) {
const SerializedStructuredCloneReadInfo srcInfo = cloneInfos[index];
const InfallibleTArray<PBlobChild*> blobs = blobArrays[index].blobsChild();
StructuredCloneReadInfo* destInfo = mCloneReadInfos.AppendElement();
if (!destInfo->SetFromSerialized(srcInfo)) {
NS_WARNING("Failed to copy clone buffer!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
IDBObjectStore::ConvertActorsToBlobs(blobs, destInfo->mFiles);
}
return NS_OK;
@ -3653,11 +3890,7 @@ nsresult
CountHelper::GetSuccessResult(JSContext* aCx,
jsval* aVal)
{
if (!JS_NewNumberValue(aCx, static_cast<double>(mCount), aVal)) {
NS_WARNING("Failed to make number value!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
*aVal = JS_NumberValue(static_cast<double>(mCount));
return NS_OK;
}

View File

@ -17,12 +17,22 @@
#include "mozilla/dom/indexedDB/IDBTransaction.h"
#include "mozilla/dom/indexedDB/KeyPath.h"
class nsIDOMBlob;
class nsIScriptContext;
class nsPIDOMWindow;
namespace mozilla {
namespace dom {
class ContentParent;
class PBlobChild;
class PBlobParent;
}
}
BEGIN_INDEXEDDB_NAMESPACE
class AsyncConnectionHelper;
class FileManager;
class IDBCursor;
class IDBKeyRange;
class IDBRequest;
@ -33,8 +43,6 @@ class Key;
struct IndexInfo;
struct IndexUpdateInfo;
struct ObjectStoreInfo;
struct StructuredCloneReadInfo;
struct StructuredCloneWriteInfo;
class IDBObjectStore MOZ_FINAL : public nsIIDBObjectStore
{
@ -103,6 +111,18 @@ public:
ConvertFileIdsToArray(const nsAString& aFileIds,
nsTArray<PRInt64>& aResult);
// Called only in the main process.
static nsresult
ConvertBlobsToActors(ContentParent* aContentParent,
FileManager* aFileManager,
const nsTArray<StructuredCloneFile>& aFiles,
InfallibleTArray<PBlobParent*>& aActors);
// Called only in the child process.
static void
ConvertActorsToBlobs(const InfallibleTArray<PBlobChild*>& aActors,
nsTArray<StructuredCloneFile>& aFiles);
const nsString& Name() const
{
return mName;
@ -183,6 +203,7 @@ public:
const SerializedStructuredCloneWriteInfo& aCloneWriteInfo,
const Key& aKey,
const InfallibleTArray<IndexUpdateInfo>& aUpdateInfoArray,
const nsTArray<nsCOMPtr<nsIDOMBlob> >& aBlobs,
bool aOverwrite,
IDBRequest** _retval);
@ -216,6 +237,7 @@ public:
size_t aDirection,
const Key& aKey,
const SerializedStructuredCloneReadInfo& aCloneInfo,
nsTArray<StructuredCloneFile>& aBlobs,
IDBCursor** _retval);
void

View File

@ -49,6 +49,20 @@ void SwapData(T& aData1, T& aData2)
aData1 = temp;
}
struct StructuredCloneFile
{
bool operator==(const StructuredCloneFile& aOther) const
{
return this->mFile == aOther.mFile &&
this->mFileInfo == aOther.mFileInfo &&
this->mInputStream == aOther.mInputStream;
}
nsCOMPtr<nsIDOMBlob> mFile;
nsRefPtr<FileInfo> mFileInfo;
nsCOMPtr<nsIInputStream> mInputStream;
};
struct SerializedStructuredCloneReadInfo;
struct StructuredCloneReadInfo
@ -59,7 +73,7 @@ struct StructuredCloneReadInfo
void Swap(StructuredCloneReadInfo& aCloneReadInfo)
{
mCloneBuffer.swap(aCloneReadInfo.mCloneBuffer);
mFileInfos.SwapElements(aCloneReadInfo.mFileInfos);
mFiles.SwapElements(aCloneReadInfo.mFiles);
SwapData(mDatabase, aCloneReadInfo.mDatabase);
}
@ -68,7 +82,7 @@ struct StructuredCloneReadInfo
SetFromSerialized(const SerializedStructuredCloneReadInfo& aOther);
JSAutoStructuredCloneBuffer mCloneBuffer;
nsTArray<nsRefPtr<FileInfo> > mFileInfos;
nsTArray<StructuredCloneFile> mFiles;
IDBDatabase* mDatabase;
};
@ -98,20 +112,6 @@ struct SerializedStructuredCloneReadInfo
size_t dataLength;
};
struct StructuredCloneFile
{
bool operator==(const StructuredCloneFile& aOther) const
{
return this->mFile == aOther.mFile &&
this->mFileInfo == aOther.mFileInfo &&
this->mInputStream == aOther.mInputStream;
}
nsCOMPtr<nsIDOMBlob> mFile;
nsRefPtr<FileInfo> mFileInfo;
nsCOMPtr<nsIInputStream> mInputStream;
};
struct SerializedStructuredCloneWriteInfo;
struct StructuredCloneWriteInfo

View File

@ -50,7 +50,7 @@ StructuredCloneReadInfo::SetFromSerialized(
return false;
}
mFileInfos.Clear();
mFiles.Clear();
return true;
}

View File

@ -217,9 +217,11 @@ IndexedDatabaseManager::GetOrCreate()
if (sIsMainProcess) {
nsCOMPtr<nsIFile> dbBaseDirectory;
rv = NS_GetSpecialDirectory(NS_APP_INDEXEDDB_PARENT_DIR, getter_AddRefs(dbBaseDirectory));
rv = NS_GetSpecialDirectory(NS_APP_INDEXEDDB_PARENT_DIR,
getter_AddRefs(dbBaseDirectory));
if (NS_FAILED(rv)) {
rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(dbBaseDirectory));
rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
getter_AddRefs(dbBaseDirectory));
}
NS_ENSURE_SUCCESS(rv, nullptr);
@ -231,9 +233,10 @@ IndexedDatabaseManager::GetOrCreate()
// Make a lazy thread for any IO we need (like clearing or enumerating the
// contents of indexedDB database directories).
instance->mIOThread = new LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS,
NS_LITERAL_CSTRING("IndexedDB I/O"),
LazyIdleThread::ManualShutdown);
instance->mIOThread =
new LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS,
NS_LITERAL_CSTRING("IndexedDB I/O"),
LazyIdleThread::ManualShutdown);
// We need one quota callback object to hand to SQLite.
instance->mQuotaCallbackSingleton = new QuotaCallback();
@ -1910,7 +1913,8 @@ IndexedDatabaseManager::InitWindowless(const jsval& aObj, JSContext* aCx)
JSObject* global = JS_GetGlobalForObject(aCx, obj);
nsRefPtr<IDBFactory> factory;
nsresult rv = IDBFactory::Create(aCx, global, getter_AddRefs(factory));
nsresult rv =
IDBFactory::Create(aCx, global, nullptr, getter_AddRefs(factory));
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
NS_ASSERTION(factory, "This should never fail for chrome!");

View File

@ -2106,10 +2106,8 @@ OpenDatabaseHelper::EnsureSuccessResult()
dbInfo->nextIndexId = mLastIndexId + 1;
nsRefPtr<IDBDatabase> database =
IDBDatabase::Create(mOpenDBRequest,
dbInfo.forget(),
mASCIIOrigin,
mFileManager);
IDBDatabase::Create(mOpenDBRequest, dbInfo.forget(), mASCIIOrigin,
mFileManager, mContentParent);
if (!database) {
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}

View File

@ -14,6 +14,12 @@
class mozIStorageConnection;
namespace mozilla {
namespace dom {
class ContentParent;
}
}
BEGIN_INDEXEDDB_NAMESPACE
class OpenDatabaseHelper : public HelperBase
@ -24,12 +30,14 @@ public:
const nsACString& aASCIIOrigin,
PRUint64 aRequestedVersion,
bool aForDeletion,
mozilla::dom::ContentParent* aContentParent,
FactoryPrivilege aPrivilege)
: HelperBase(aRequest), mOpenDBRequest(aRequest), mName(aName),
mASCIIOrigin(aASCIIOrigin), mRequestedVersion(aRequestedVersion),
mForDeletion(aForDeletion), mPrivilege(aPrivilege), mDatabaseId(nullptr),
mCurrentVersion(0), mLastObjectStoreId(0), mLastIndexId(0),
mState(eCreated), mResultCode(NS_OK), mLoadDBMetadata(false)
mContentParent(aContentParent), mCurrentVersion(0), mLastObjectStoreId(0),
mLastIndexId(0), mState(eCreated), mResultCode(NS_OK),
mLoadDBMetadata(false)
{
NS_ASSERTION(!aForDeletion || !aRequestedVersion,
"Can't be for deletion and request a version!");
@ -103,6 +111,7 @@ protected:
bool mForDeletion;
FactoryPrivilege mPrivilege;
nsCOMPtr<nsIAtom> mDatabaseId;
mozilla::dom::ContentParent* mContentParent;
// Out-params.
nsTArray<nsRefPtr<ObjectStoreInfo> > mObjectStores;
@ -133,4 +142,4 @@ protected:
END_INDEXEDDB_NAMESPACE
#endif // mozilla_dom_indexeddb_opendatabasehelper_h__
#endif // mozilla_dom_indexeddb_opendatabasehelper_h__

View File

@ -6,10 +6,11 @@
#include "IndexedDBChild.h"
#include "mozilla/Assertions.h"
#include "nsIAtom.h"
#include "mozilla/Assertions.h"
#include "mozilla/dom/ContentChild.h"
#include "AsyncConnectionHelper.h"
#include "DatabaseInfo.h"
#include "IDBEvents.h"
@ -21,6 +22,8 @@
USING_INDEXEDDB_NAMESPACE
using namespace mozilla::dom;
namespace {
class IPCOpenDatabaseHelper : public AsyncConnectionHelper
@ -289,7 +292,8 @@ IndexedDBDatabaseChild::EnsureDatabase(
if (!mDatabase) {
nsRefPtr<IDBDatabase> database =
IDBDatabase::Create(aRequest, dbInfo.forget(), aDBInfo.origin, NULL);
IDBDatabase::Create(aRequest, dbInfo.forget(), aDBInfo.origin, NULL,
NULL);
if (!database) {
NS_WARNING("Failed to create database!");
return false;
@ -646,13 +650,18 @@ IndexedDBObjectStoreChild::RecvPIndexedDBCursorConstructor(
size_t direction = static_cast<size_t>(aParams.direction());
nsTArray<StructuredCloneFile> blobs;
IDBObjectStore::ConvertActorsToBlobs(aParams.blobsChild(), blobs);
nsRefPtr<IDBCursor> cursor;
nsresult rv =
mObjectStore->OpenCursorFromChildProcess(request, direction, aParams.key(),
aParams.cloneInfo(),
aParams.cloneInfo(), blobs,
getter_AddRefs(cursor));
NS_ENSURE_SUCCESS(rv, false);
MOZ_ASSERT(blobs.IsEmpty(), "Should have swapped blob elements!");
actor->SetCursor(cursor);
return true;
}
@ -754,16 +763,22 @@ IndexedDBIndexChild::RecvPIndexedDBCursorConstructor(
switch (aParams.optionalCloneInfo().type()) {
case CursorUnionType::TSerializedStructuredCloneReadInfo: {
nsTArray<StructuredCloneFile> blobs;
IDBObjectStore::ConvertActorsToBlobs(aParams.blobsChild(), blobs);
const SerializedStructuredCloneReadInfo& cloneInfo =
aParams.optionalCloneInfo().get_SerializedStructuredCloneReadInfo();
rv = mIndex->OpenCursorFromChildProcess(request, direction, aParams.key(),
aParams.objectKey(), cloneInfo,
blobs,
getter_AddRefs(cursor));
NS_ENSURE_SUCCESS(rv, false);
} break;
case CursorUnionType::Tvoid_t:
MOZ_ASSERT(aParams.blobsChild().IsEmpty());
rv = mIndex->OpenCursorFromChildProcess(request, direction, aParams.key(),
aParams.objectKey(),
getter_AddRefs(cursor));

View File

@ -6,12 +6,15 @@
#include "IndexedDBParent.h"
#include "nsIDOMFile.h"
#include "nsIDOMEvent.h"
#include "nsIIDBVersionChangeEvent.h"
#include "nsIJSContextStack.h"
#include "nsIXPConnect.h"
#include "mozilla/Assertions.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/ipc/Blob.h"
#include "nsContentUtils.h"
#include "AsyncConnectionHelper.h"
@ -26,6 +29,8 @@
USING_INDEXEDDB_NAMESPACE
using namespace mozilla::dom;
/*******************************************************************************
* AutoSetCurrentTransaction
******************************************************************************/
@ -1183,6 +1188,29 @@ IndexedDBObjectStoreRequestParent::~IndexedDBObjectStoreRequestParent()
MOZ_COUNT_DTOR(IndexedDBObjectStoreRequestParent);
}
void
IndexedDBObjectStoreRequestParent::ConvertBlobActors(
const InfallibleTArray<PBlobParent*>& aActors,
nsTArray<nsCOMPtr<nsIDOMBlob> >& aBlobs)
{
MOZ_ASSERT(aBlobs.IsEmpty());
if (!aActors.IsEmpty()) {
// Walk the chain to get to ContentParent.
ContentParent* contentParent =
mObjectStore->Transaction()->Database()->GetContentParent();
MOZ_ASSERT(contentParent);
uint32_t length = aActors.Length();
aBlobs.SetCapacity(length);
for (uint32_t index = 0; index < length; index++) {
BlobParent* actor = static_cast<BlobParent*>(aActors[index]);
aBlobs.AppendElement(actor->GetBlob());
}
}
}
bool
IndexedDBObjectStoreRequestParent::Get(const GetParams& aParams)
{
@ -1254,6 +1282,9 @@ IndexedDBObjectStoreRequestParent::Add(const AddParams& aParams)
ipc::AddPutParams params = aParams.commonParams();
nsTArray<nsCOMPtr<nsIDOMBlob> > blobs;
ConvertBlobActors(params.blobsParent(), blobs);
nsRefPtr<IDBRequest> request;
{
@ -1261,7 +1292,7 @@ IndexedDBObjectStoreRequestParent::Add(const AddParams& aParams)
nsresult rv =
mObjectStore->AddOrPutInternal(params.cloneInfo(), params.key(),
params.indexUpdateInfos(), false,
params.indexUpdateInfos(), blobs, false,
getter_AddRefs(request));
NS_ENSURE_SUCCESS(rv, false);
}
@ -1278,6 +1309,9 @@ IndexedDBObjectStoreRequestParent::Put(const PutParams& aParams)
ipc::AddPutParams params = aParams.commonParams();
nsTArray<nsCOMPtr<nsIDOMBlob> > blobs;
ConvertBlobActors(params.blobsParent(), blobs);
nsRefPtr<IDBRequest> request;
{
@ -1285,7 +1319,7 @@ IndexedDBObjectStoreRequestParent::Put(const PutParams& aParams)
nsresult rv =
mObjectStore->AddOrPutInternal(params.cloneInfo(), params.key(),
params.indexUpdateInfos(), true,
params.indexUpdateInfos(), blobs, true,
getter_AddRefs(request));
NS_ENSURE_SUCCESS(rv, false);
}

View File

@ -23,10 +23,12 @@
namespace mozilla {
namespace dom {
class ContentParent;
class PBlobParent;
class TabParent;
}
}
class nsIDOMBlob;
class nsIDOMEvent;
BEGIN_INDEXEDDB_NAMESPACE
@ -531,6 +533,11 @@ public:
bool
OpenCursor(const OpenCursorParams& aParams);
protected:
void
ConvertBlobActors(const InfallibleTArray<PBlobParent*>& aActors,
nsTArray<nsCOMPtr<nsIDOMBlob> >& aBlobs);
};
/*******************************************************************************

View File

@ -48,4 +48,4 @@ copy-xpcshell-tests:
$(call install_cmd,$(wildcard $(topsrcdir)/dom/indexedDB/test/unit/test_*.js) \
$(testxpcobjdir)/$(relativesrcdir)/$(XPCSHELL_TESTS))
libs-xpcshell-tests: copy-xpcshell-tests
libs-xpcshell-tests: copy-xpcshell-tests

View File

@ -2,6 +2,7 @@
* 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 protocol PBlob;
include protocol PIndexedDBCursor;
include protocol PIndexedDBObjectStore;
include protocol PIndexedDBRequest;
@ -102,6 +103,7 @@ struct IndexCursorConstructorParams
Key key;
Key objectKey;
OptionalStructuredCloneReadInfo optionalCloneInfo;
PBlob[] blobs;
};
} // namespace ipc

View File

@ -2,6 +2,7 @@
* 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 protocol PBlob;
include protocol PIndexedDBCursor;
include protocol PIndexedDBIndex;
include protocol PIndexedDBRequest;
@ -70,6 +71,7 @@ struct AddPutParams
SerializedStructuredCloneWriteInfo cloneInfo;
Key key;
IndexUpdateInfo[] indexUpdateInfos;
PBlob[] blobs;
};
struct AddParams
@ -126,6 +128,7 @@ struct ObjectStoreCursorConstructorParams
Direction direction;
Key key;
SerializedStructuredCloneReadInfo cloneInfo;
PBlob[] blobs;
};
} // namespace ipc

View File

@ -2,6 +2,7 @@
* 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 protocol PBlob;
include protocol PIndexedDBCursor;
include protocol PIndexedDBIndex;
include protocol PIndexedDBObjectStore;
@ -22,6 +23,7 @@ namespace ipc {
struct GetResponse
{
SerializedStructuredCloneReadInfo cloneInfo;
PBlob[] blobs;
};
struct GetKeyResponse
@ -29,9 +31,15 @@ struct GetKeyResponse
Key key;
};
struct BlobArray
{
PBlob[] blobs;
};
struct GetAllResponse
{
SerializedStructuredCloneReadInfo[] cloneInfos;
BlobArray[] blobs;
};
struct GetAllKeysResponse
@ -75,6 +83,7 @@ struct ContinueResponse
Key key;
Key objectKey;
SerializedStructuredCloneReadInfo cloneInfo;
PBlob[] blobs;
};
union ResponseValue

View File

@ -29,6 +29,7 @@ MOCHITEST_FILES = \
test_autoIncrement_indexes.html \
test_autoIncrement.html \
test_bfcache.html \
test_blob_simple.html \
test_clear.html \
test_complex_keyPaths.html \
test_count.html \

View File

@ -0,0 +1,192 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>Indexed Database Property Test</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript;version=1.7">
function testSteps()
{
const BLOB_DATA = ["fun ", "times ", "all ", "around!"];
const INDEX_KEY = 5;
let request = indexedDB.open(window.location.pathname, 1);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = unexpectedSuccessHandler;
let event = yield;
let db = event.target.result;
db.onerror = errorHandler;
let objectStore = db.createObjectStore("foo", { autoIncrement: true });
let index = objectStore.createIndex("foo", "index");
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let blob = new Blob(BLOB_DATA, { type: "text/plain" });
let data = { blob: blob, index: INDEX_KEY };
objectStore = db.transaction("foo", "readwrite").objectStore("foo");
objectStore.add(data).onsuccess = grabEventAndContinueHandler;
event = yield;
let key = event.target.result;
objectStore.add(data).onsuccess = grabEventAndContinueHandler;
event = yield;
objectStore = db.transaction("foo").objectStore("foo");
objectStore.get(key).onsuccess = grabEventAndContinueHandler;
event = yield;
let fileReader = new FileReader();
fileReader.onload = grabEventAndContinueHandler;
fileReader.readAsText(event.target.result.blob);
event = yield;
is(event.target.result, BLOB_DATA.join(""), "Correct text");
objectStore = db.transaction("foo").objectStore("foo");
objectStore.mozGetAll().onsuccess = grabEventAndContinueHandler;
event = yield;
is(event.target.result.length, 2, "Got right number of items");
fileReader = new FileReader();
fileReader.onload = grabEventAndContinueHandler;
fileReader.readAsText(event.target.result[0].blob);
event = yield;
is(event.target.result, BLOB_DATA.join(""), "Correct text");
let cursorResults = [];
objectStore = db.transaction("foo").objectStore("foo");
objectStore.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
cursorResults.push(cursor.value);
cursor.continue();
}
else {
continueToNextStep();
}
};
yield;
is(cursorResults.length, 2, "Got right number of items");
fileReader = new FileReader();
fileReader.onload = grabEventAndContinueHandler;
fileReader.readAsText(cursorResults[0].blob);
event = yield;
is(event.target.result, BLOB_DATA.join(""), "Correct text");
let index = db.transaction("foo").objectStore("foo").index("foo");
index.get(INDEX_KEY).onsuccess = grabEventAndContinueHandler;
event = yield;
fileReader = new FileReader();
fileReader.onload = grabEventAndContinueHandler;
fileReader.readAsText(event.target.result.blob);
event = yield;
is(event.target.result, BLOB_DATA.join(""), "Correct text");
index = db.transaction("foo").objectStore("foo").index("foo");
index.mozGetAll().onsuccess = grabEventAndContinueHandler;
event = yield;
is(event.target.result.length, 2, "Got right number of items");
fileReader = new FileReader();
fileReader.onload = grabEventAndContinueHandler;
fileReader.readAsText(event.target.result[0].blob);
event = yield;
is(event.target.result, BLOB_DATA.join(""), "Correct text");
cursorResults = [];
index = db.transaction("foo").objectStore("foo").index("foo");
index.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
cursorResults.push(cursor.value);
cursor.continue();
}
else {
continueToNextStep();
}
};
yield;
is(cursorResults.length, 2, "Got right number of items");
fileReader = new FileReader();
fileReader.onload = grabEventAndContinueHandler;
fileReader.readAsText(cursorResults[0].blob);
event = yield;
is(event.target.result, BLOB_DATA.join(""), "Correct text");
fileReader = new FileReader();
fileReader.onload = grabEventAndContinueHandler;
fileReader.readAsText(cursorResults[1].blob);
event = yield;
is(event.target.result, BLOB_DATA.join(""), "Correct text");
let slice = cursorResults[1].blob.slice(0, BLOB_DATA[0].length);
fileReader = new FileReader();
fileReader.onload = grabEventAndContinueHandler;
fileReader.readAsText(slice);
event = yield;
is(event.target.result, BLOB_DATA[0], "Correct text");
function workerScript() {
onmessage = function(event) {
var reader = new FileReaderSync();
postMessage(reader.readAsText(event.data));
var slice = event.data.slice(1, 2);
postMessage(reader.readAsText(slice));
}
}
let url =
URL.createObjectURL(new Blob(["(", workerScript.toSource(), ")()"]));
let worker = new Worker(url);
worker.postMessage(slice);
worker.onmessage = grabEventAndContinueHandler;
event = yield;
is(event.data, BLOB_DATA[0], "Correct text");
event = yield;
is(event.data, BLOB_DATA[0][1], "Correct text");
finishTest();
yield;
}
</script>
<script type="text/javascript;version=1.7" src="file.js"></script>
<script type="text/javascript;version=1.7" src="helpers.js"></script>
</head>
<body onload="runTest();"></body>
</html>

View File

@ -32,6 +32,7 @@ XPIDLSRCS = \
nsIDOMCSSImportRule.idl \
nsIDOMCSSMediaRule.idl \
nsIDOMCSSMozDocumentRule.idl \
nsIDOMCSSSupportsRule.idl \
nsIDOMMozCSSKeyframeRule.idl \
nsIDOMMozCSSKeyframesRule.idl \
nsIDOMCSSPageRule.idl \

View File

@ -27,6 +27,7 @@ interface nsIDOMCSSRule : nsISupports
const unsigned short MOZ_KEYFRAMES_RULE = 7;
const unsigned short MOZ_KEYFRAME_RULE = 8;
const unsigned short NAMESPACE_RULE = 10;
const unsigned short SUPPORTS_RULE = 12;
readonly attribute unsigned short type;
attribute DOMString cssText;

View File

@ -0,0 +1,21 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "nsIDOMCSSRule.idl"
/**
* Interface for @supports rules in the CSS OM.
*/
[scriptable, uuid(5f409a4d-92f9-4a62-8e8a-cc1c02c32918)]
interface nsIDOMCSSSupportsRule : nsIDOMCSSRule
{
readonly attribute nsIDOMCSSRuleList cssRules;
unsigned long insertRule(in DOMString rule,
in unsigned long index)
raises(DOMException);
void deleteRule(in unsigned long index)
raises(DOMException);
};

View File

@ -20,7 +20,8 @@ include $(topsrcdir)/dom/dom-config.mk
XPIDLSRCS = \
nsIDOMDeviceStorage.idl \
nsIDOMDeviceStorageCursor.idl \
nsIDOMNavigatorDeviceStorage.idl
nsIDOMNavigatorDeviceStorage.idl \
nsIDOMDeviceStorageChangeEvent.idl
include $(topsrcdir)/config/rules.mk

View File

@ -3,24 +3,22 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "domstubs.idl"
#include "nsIDOMEventTarget.idl"
interface nsIDOMBlob;
interface nsIDOMDOMRequest;
interface nsIDOMDeviceStorageCursor;
interface nsIDOMDeviceStorageChangeEvent;
interface nsIDOMEventListener;
dictionary DeviceStorageEnumerationParameters
{
jsval since;
};
[scriptable, uuid(05C0D0C8-D698-4CCD-899C-7198A33BD7EC)]
interface nsIDOMDeviceStorage : nsISupports
[scriptable, uuid(3dbe0137-ca73-44c5-bcde-25c297bf7c65), builtinclass]
interface nsIDOMDeviceStorage : nsIDOMEventTarget
{
/*
* Hint as to what kind of storage this object is.
* May be "external", "shared", or "default".
*/
readonly attribute DOMString type;
attribute nsIDOMEventListener onchange;
nsIDOMDOMRequest add(in nsIDOMBlob aBlob);
nsIDOMDOMRequest addNamed(in nsIDOMBlob aBlob, in DOMString aName);

View File

@ -0,0 +1,19 @@
/* 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 "domstubs.idl"
#include "nsIDOMEvent.idl"
[scriptable, uuid(468304d6-aab6-4e1e-8ab2-569d9e703431), builtinclass]
interface nsIDOMDeviceStorageChangeEvent : nsIDOMEvent
{
readonly attribute DOMString path;
readonly attribute DOMString reason;
};
dictionary DeviceStorageChangeEventInit : EventInit
{
DOMString path;
DOMString reason;
};

View File

@ -3,15 +3,13 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "domstubs.idl"
interface nsIVariant;
interface nsIDOMDeviceStorage;
/**
* Property that extends the navigator object.
*/
[scriptable, uuid(A4B2831D-6065-472F-8A6D-2C9085C74C15)]
[scriptable, uuid(da1fbf6e-259c-40bc-ba8c-4ae81748dca3)]
interface nsIDOMNavigatorDeviceStorage : nsISupports
{
// returns an array of nsIDOMDeviceStorage
nsIVariant getDeviceStorage(in DOMString type);
nsIDOMDeviceStorage getDeviceStorage(in DOMString type);
};

797
dom/ipc/Blob.cpp Normal file
View File

@ -0,0 +1,797 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set sw=4 ts=8 et tw=80 : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "base/basictypes.h"
#include "Blob.h"
#include "nsIDOMFile.h"
#include "nsIInputStream.h"
#include "nsIRemoteBlob.h"
#include "nsISeekableStream.h"
#include "mozilla/Assertions.h"
#include "mozilla/Monitor.h"
#include "mozilla/net/NeckoMessageUtils.h"
#include "nsDOMFile.h"
#include "nsThreadUtils.h"
#include "ContentChild.h"
#include "ContentParent.h"
using namespace mozilla::dom;
using namespace mozilla::dom::ipc;
namespace {
class RemoteInputStream : public nsIInputStream,
public nsISeekableStream
{
mozilla::Monitor mMonitor;
nsCOMPtr<nsIDOMBlob> mSourceBlob;
nsCOMPtr<nsIInputStream> mStream;
nsCOMPtr<nsISeekableStream> mSeekableStream;
public:
NS_DECL_ISUPPORTS
RemoteInputStream(nsIDOMBlob* aSourceBlob)
: mMonitor("RemoteInputStream.mMonitor"), mSourceBlob(aSourceBlob)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aSourceBlob);
}
void
SetStream(nsIInputStream* aStream)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aStream);
nsCOMPtr<nsIInputStream> stream = aStream;
nsCOMPtr<nsISeekableStream> seekableStream = do_QueryInterface(aStream);
{
mozilla::MonitorAutoLock lock(mMonitor);
MOZ_ASSERT(!mStream);
MOZ_ASSERT(!mSeekableStream);
mStream.swap(stream);
mSeekableStream.swap(seekableStream);
mMonitor.Notify();
}
}
NS_IMETHOD
Close() MOZ_OVERRIDE
{
nsresult rv = BlockAndWaitForStream();
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOMBlob> sourceBlob;
mSourceBlob.swap(sourceBlob);
rv = mStream->Close();
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHOD
Available(PRUint32* aAvailable) MOZ_OVERRIDE
{
// See large comment in FileInputStreamWrapper::Available.
if (NS_IsMainThread()) {
return NS_BASE_STREAM_CLOSED;
}
nsresult rv = BlockAndWaitForStream();
NS_ENSURE_SUCCESS(rv, rv);
rv = mStream->Available(aAvailable);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHOD
Read(char* aBuffer, PRUint32 aCount, PRUint32* aResult) MOZ_OVERRIDE
{
nsresult rv = BlockAndWaitForStream();
NS_ENSURE_SUCCESS(rv, rv);
rv = mStream->Read(aBuffer, aCount, aResult);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHOD
ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, PRUint32 aCount,
PRUint32* aResult) MOZ_OVERRIDE
{
nsresult rv = BlockAndWaitForStream();
NS_ENSURE_SUCCESS(rv, rv);
rv = mStream->ReadSegments(aWriter, aClosure, aCount, aResult);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHOD
IsNonBlocking(bool* aNonBlocking) MOZ_OVERRIDE
{
NS_ENSURE_ARG_POINTER(aNonBlocking);
*aNonBlocking = false;
return NS_OK;
}
NS_IMETHOD
Seek(PRInt32 aWhence, PRInt64 aOffset) MOZ_OVERRIDE
{
nsresult rv = BlockAndWaitForStream();
NS_ENSURE_SUCCESS(rv, rv);
if (!mSeekableStream) {
NS_WARNING("Underlying blob stream is not seekable!");
return NS_ERROR_NO_INTERFACE;
}
rv = mSeekableStream->Seek(aWhence, aOffset);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHOD
Tell(PRInt64* aResult)
{
nsresult rv = BlockAndWaitForStream();
NS_ENSURE_SUCCESS(rv, rv);
if (!mSeekableStream) {
NS_WARNING("Underlying blob stream is not seekable!");
return NS_ERROR_NO_INTERFACE;
}
rv = mSeekableStream->Tell(aResult);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHOD
SetEOF()
{
nsresult rv = BlockAndWaitForStream();
NS_ENSURE_SUCCESS(rv, rv);
if (!mSeekableStream) {
NS_WARNING("Underlying blob stream is not seekable!");
return NS_ERROR_NO_INTERFACE;
}
rv = mSeekableStream->SetEOF();
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
private:
virtual ~RemoteInputStream()
{ }
void
ReallyBlockAndWaitForStream()
{
mozilla::MonitorAutoLock lock(mMonitor);
while (!mStream) {
mMonitor.Wait();
}
}
nsresult
BlockAndWaitForStream()
{
if (NS_IsMainThread()) {
NS_WARNING("Blocking the main thread is not supported!");
return NS_ERROR_FAILURE;
}
ReallyBlockAndWaitForStream();
return NS_OK;
}
bool
IsSeekableStream()
{
if (NS_IsMainThread()) {
if (!mStream) {
NS_WARNING("Don't know if this stream is seekable yet!");
return true;
}
}
else {
ReallyBlockAndWaitForStream();
}
return !!mSeekableStream;
}
};
template <ActorFlavorEnum ActorFlavor>
class InputStreamActor : public BlobTraits<ActorFlavor>::StreamType
{
typedef typename BlobTraits<ActorFlavor>::StreamType::InputStream InputStream;
nsRefPtr<RemoteInputStream> mRemoteStream;
public:
InputStreamActor(RemoteInputStream* aRemoteStream)
: mRemoteStream(aRemoteStream)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aRemoteStream);
}
InputStreamActor()
{
MOZ_ASSERT(NS_IsMainThread());
}
private:
// This method is only called by the IPDL message machinery.
virtual bool
Recv__delete__(const InputStream& aStream) MOZ_OVERRIDE
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mRemoteStream);
mRemoteStream->SetStream(aStream);
return true;
}
};
template <ActorFlavorEnum ActorFlavor>
inline
already_AddRefed<nsIDOMBlob>
GetBlobFromParams(const SlicedBlobConstructorParams& aParams)
{
MOZ_STATIC_ASSERT(ActorFlavor == mozilla::dom::ipc::Parent,
"No other flavor is supported here!");
BlobParent* actor =
const_cast<BlobParent*>(
static_cast<const BlobParent*>(aParams.sourceParent()));
MOZ_ASSERT(actor);
return actor->GetBlob();
}
template <>
inline
already_AddRefed<nsIDOMBlob>
GetBlobFromParams<Child>(const SlicedBlobConstructorParams& aParams)
{
BlobChild* actor =
const_cast<BlobChild*>(
static_cast<const BlobChild*>(aParams.sourceChild()));
MOZ_ASSERT(actor);
return actor->GetBlob();
}
inline
void
SetBlobOnParams(BlobChild* aActor, SlicedBlobConstructorParams& aParams)
{
aParams.sourceChild() = aActor;
}
inline
void
SetBlobOnParams(BlobParent* aActor, SlicedBlobConstructorParams& aParams)
{
aParams.sourceParent() = aActor;
}
} // anonymous namespace
namespace mozilla {
namespace dom {
namespace ipc {
template <ActorFlavorEnum ActorFlavor>
class RemoteBlob : public nsDOMFile,
public nsIRemoteBlob
{
public:
typedef RemoteBlob<ActorFlavor> SelfType;
typedef Blob<ActorFlavor> ActorType;
typedef InputStreamActor<ActorFlavor> StreamActorType;
private:
ActorType* mActor;
class StreamHelper : public nsRunnable
{
typedef Blob<ActorFlavor> ActorType;
typedef InputStreamActor<ActorFlavor> StreamActorType;
mozilla::Monitor mMonitor;
ActorType* mActor;
nsCOMPtr<nsIDOMBlob> mSourceBlob;
nsRefPtr<RemoteInputStream> mInputStream;
bool mDone;
public:
StreamHelper(ActorType* aActor, nsIDOMBlob* aSourceBlob)
: mMonitor("RemoteBlob::StreamHelper::mMonitor"), mActor(aActor),
mSourceBlob(aSourceBlob), mDone(false)
{
// This may be created on any thread.
MOZ_ASSERT(aActor);
MOZ_ASSERT(aSourceBlob);
}
nsresult
GetStream(nsIInputStream** aInputStream)
{
// This may be called on any thread.
MOZ_ASSERT(aInputStream);
MOZ_ASSERT(mActor);
MOZ_ASSERT(!mInputStream);
MOZ_ASSERT(!mDone);
if (NS_IsMainThread()) {
RunInternal(false);
}
else {
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
NS_ENSURE_TRUE(mainThread, NS_ERROR_FAILURE);
nsresult rv = mainThread->Dispatch(this, NS_DISPATCH_NORMAL);
NS_ENSURE_SUCCESS(rv, rv);
{
MonitorAutoLock lock(mMonitor);
while (!mDone) {
lock.Wait();
}
}
}
MOZ_ASSERT(!mActor);
MOZ_ASSERT(mDone);
if (!mInputStream) {
return NS_ERROR_UNEXPECTED;
}
mInputStream.forget(aInputStream);
return NS_OK;
}
NS_IMETHOD
Run()
{
MOZ_ASSERT(NS_IsMainThread());
RunInternal(true);
return NS_OK;
}
private:
void
RunInternal(bool aNotify)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mActor);
MOZ_ASSERT(!mInputStream);
MOZ_ASSERT(!mDone);
nsRefPtr<RemoteInputStream> stream = new RemoteInputStream(mSourceBlob);
StreamActorType* streamActor = new StreamActorType(stream);
if (mActor->SendPBlobStreamConstructor(streamActor)) {
stream.swap(mInputStream);
}
mActor = nullptr;
if (aNotify) {
MonitorAutoLock lock(mMonitor);
mDone = true;
lock.Notify();
}
else {
mDone = true;
}
}
};
class SliceHelper : public nsRunnable
{
typedef Blob<ActorFlavor> ActorType;
mozilla::Monitor mMonitor;
ActorType* mActor;
nsCOMPtr<nsIDOMBlob> mSlice;
PRUint64 mStart;
PRUint64 mLength;
nsString mContentType;
bool mDone;
public:
SliceHelper(ActorType* aActor)
: mMonitor("RemoteBlob::SliceHelper::mMonitor"), mActor(aActor), mStart(0),
mLength(0), mDone(false)
{
// This may be created on any thread.
MOZ_ASSERT(aActor);
}
nsresult
GetSlice(PRUint64 aStart, PRUint64 aLength, const nsAString& aContentType,
nsIDOMBlob** aSlice)
{
// This may be called on any thread.
MOZ_ASSERT(aSlice);
MOZ_ASSERT(mActor);
MOZ_ASSERT(!mSlice);
MOZ_ASSERT(!mDone);
mStart = aStart;
mLength = aLength;
mContentType = aContentType;
if (NS_IsMainThread()) {
RunInternal(false);
}
else {
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
NS_ENSURE_TRUE(mainThread, NS_ERROR_FAILURE);
nsresult rv = mainThread->Dispatch(this, NS_DISPATCH_NORMAL);
NS_ENSURE_SUCCESS(rv, rv);
{
MonitorAutoLock lock(mMonitor);
while (!mDone) {
lock.Wait();
}
}
}
MOZ_ASSERT(!mActor);
MOZ_ASSERT(mDone);
if (!mSlice) {
return NS_ERROR_UNEXPECTED;
}
mSlice.forget(aSlice);
return NS_OK;
}
NS_IMETHOD
Run()
{
MOZ_ASSERT(NS_IsMainThread());
RunInternal(true);
return NS_OK;
}
private:
void
RunInternal(bool aNotify)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mActor);
MOZ_ASSERT(!mSlice);
MOZ_ASSERT(!mDone);
NormalBlobConstructorParams normalParams;
normalParams.contentType() = mContentType;
normalParams.length() = mLength;
ActorType* newActor = ActorType::Create(normalParams);
MOZ_ASSERT(newActor);
SlicedBlobConstructorParams slicedParams;
slicedParams.contentType() = mContentType;
slicedParams.begin() = mStart;
slicedParams.end() = mStart + mLength;
SetBlobOnParams(mActor, slicedParams);
if (mActor->Manager()->SendPBlobConstructor(newActor, slicedParams)) {
mSlice = newActor->GetBlob();
}
mActor = nullptr;
if (aNotify) {
MonitorAutoLock lock(mMonitor);
mDone = true;
lock.Notify();
}
else {
mDone = true;
}
}
};
public:
NS_DECL_ISUPPORTS_INHERITED
RemoteBlob(const nsAString& aName, const nsAString& aContentType,
PRUint64 aLength)
: nsDOMFile(aName, aContentType, aLength), mActor(nullptr)
{ }
RemoteBlob(const nsAString& aContentType, PRUint64 aLength)
: nsDOMFile(aContentType, aLength), mActor(nullptr)
{ }
virtual ~RemoteBlob()
{
if (mActor) {
mActor->NoteDyingRemoteBlob();
}
}
void
SetActor(ActorType* aActor)
{
MOZ_ASSERT(!aActor || !mActor);
mActor = aActor;
}
virtual already_AddRefed<nsIDOMBlob>
CreateSlice(PRUint64 aStart, PRUint64 aLength, const nsAString& aContentType)
MOZ_OVERRIDE
{
if (!mActor) {
return nullptr;
}
nsRefPtr<SliceHelper> helper = new SliceHelper(mActor);
nsCOMPtr<nsIDOMBlob> slice;
nsresult rv =
helper->GetSlice(aStart, aLength, aContentType, getter_AddRefs(slice));
NS_ENSURE_SUCCESS(rv, nullptr);
return slice.forget();
}
NS_IMETHOD
GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE
{
if (!mActor) {
return NS_ERROR_UNEXPECTED;
}
nsRefPtr<StreamHelper> helper = new StreamHelper(mActor, this);
return helper->GetStream(aStream);
}
virtual void*
GetPBlob() MOZ_OVERRIDE
{
return static_cast<typename ActorType::BaseType*>(mActor);
}
};
} // namespace ipc
} // namespace dom
} // namespace mozilla
template <ActorFlavorEnum ActorFlavor>
Blob<ActorFlavor>::Blob(nsIDOMBlob* aBlob)
: mBlob(aBlob), mRemoteBlob(nullptr), mOwnsBlob(true)
{
MOZ_ASSERT(aBlob);
aBlob->AddRef();
}
template <ActorFlavorEnum ActorFlavor>
Blob<ActorFlavor>::Blob(const BlobConstructorParams& aParams)
: mBlob(nullptr), mRemoteBlob(nullptr), mOwnsBlob(true)
{
nsRefPtr<RemoteBlobType> remoteBlob;
switch (aParams.type()) {
case BlobConstructorParams::TNormalBlobConstructorParams: {
const NormalBlobConstructorParams& params =
aParams.get_NormalBlobConstructorParams();
remoteBlob = new RemoteBlobType(params.contentType(), params.length());
break;
}
case BlobConstructorParams::TFileBlobConstructorParams: {
const FileBlobConstructorParams& params =
aParams.get_FileBlobConstructorParams();
remoteBlob =
new RemoteBlobType(params.name(), params.contentType(),
params.length());
break;
}
default:
MOZ_NOT_REACHED("Unknown params!");
}
MOZ_ASSERT(remoteBlob);
if (NS_FAILED(remoteBlob->SetMutable(false))) {
MOZ_NOT_REACHED("Failed to make remote blob immutable!");
}
remoteBlob->SetActor(this);
remoteBlob.forget(&mRemoteBlob);
mBlob = mRemoteBlob;
}
template <ActorFlavorEnum ActorFlavor>
Blob<ActorFlavor>*
Blob<ActorFlavor>::Create(const BlobConstructorParams& aParams)
{
switch (aParams.type()) {
case BlobConstructorParams::TNormalBlobConstructorParams:
case BlobConstructorParams::TFileBlobConstructorParams:
return new Blob<ActorFlavor>(aParams);
case BlobConstructorParams::TSlicedBlobConstructorParams: {
const SlicedBlobConstructorParams& params =
aParams.get_SlicedBlobConstructorParams();
nsCOMPtr<nsIDOMBlob> source = GetBlobFromParams<ActorFlavor>(params);
MOZ_ASSERT(source);
nsCOMPtr<nsIDOMBlob> slice;
nsresult rv =
source->Slice(params.begin(), params.end(), params.contentType(), 3,
getter_AddRefs(slice));
NS_ENSURE_SUCCESS(rv, nullptr);
return new Blob<ActorFlavor>(slice);
}
default:
MOZ_NOT_REACHED("Unknown params!");
}
return nullptr;
}
template <ActorFlavorEnum ActorFlavor>
already_AddRefed<nsIDOMBlob>
Blob<ActorFlavor>::GetBlob()
{
MOZ_ASSERT(mBlob);
nsCOMPtr<nsIDOMBlob> blob;
// Remote blobs are held alive until the first call to GetBlob. Thereafter we
// only hold a weak reference. Normal blobs are held alive until the actor is
// destroyed.
if (mRemoteBlob && mOwnsBlob) {
blob = dont_AddRef(mBlob);
mOwnsBlob = false;
}
else {
blob = mBlob;
}
MOZ_ASSERT(blob);
return blob.forget();
}
template <ActorFlavorEnum ActorFlavor>
void
Blob<ActorFlavor>::NoteDyingRemoteBlob()
{
MOZ_ASSERT(mBlob);
MOZ_ASSERT(mRemoteBlob);
MOZ_ASSERT(!mOwnsBlob);
if (!NS_IsMainThread()) {
nsCOMPtr<nsIRunnable> runnable =
NS_NewNonOwningRunnableMethod(this,
&Blob<ActorFlavor>::NoteDyingRemoteBlob);
if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
MOZ_NOT_REACHED("Should never fail!");
}
return;
}
// Must do this before calling Send__delete__ or we'll crash there trying to
// access a dangling pointer.
mRemoteBlob = nullptr;
BaseType::Send__delete__(this);
}
template <ActorFlavorEnum ActorFlavor>
void
Blob<ActorFlavor>::ActorDestroy(ActorDestroyReason aWhy)
{
MOZ_ASSERT(mBlob);
if (mRemoteBlob) {
mRemoteBlob->SetActor(nullptr);
}
if (mOwnsBlob) {
mBlob->Release();
}
}
template <ActorFlavorEnum ActorFlavor>
bool
Blob<ActorFlavor>::RecvPBlobStreamConstructor(StreamType* aActor)
{
MOZ_ASSERT(mBlob);
MOZ_ASSERT(!mRemoteBlob);
nsCOMPtr<nsIInputStream> stream;
nsresult rv = mBlob->GetInternalStream(getter_AddRefs(stream));
NS_ENSURE_SUCCESS(rv, false);
return aActor->Send__delete__(aActor, stream.get());
}
template <ActorFlavorEnum ActorFlavor>
typename Blob<ActorFlavor>::StreamType*
Blob<ActorFlavor>::AllocPBlobStream()
{
return new InputStreamActor<ActorFlavor>();
}
template <ActorFlavorEnum ActorFlavor>
bool
Blob<ActorFlavor>::DeallocPBlobStream(StreamType* aActor)
{
delete aActor;
return true;
}
template <ActorFlavorEnum ActorFlavor>
NS_IMPL_ADDREF_INHERITED(RemoteBlob<ActorFlavor>, nsDOMFile)
template <ActorFlavorEnum ActorFlavor>
NS_IMPL_RELEASE_INHERITED(RemoteBlob<ActorFlavor>, nsDOMFile)
template <ActorFlavorEnum ActorFlavor>
NS_IMPL_QUERY_INTERFACE_INHERITED1(RemoteBlob<ActorFlavor>, nsDOMFile,
nsIRemoteBlob)
NS_IMPL_THREADSAFE_ADDREF(RemoteInputStream)
NS_IMPL_THREADSAFE_RELEASE(RemoteInputStream)
NS_INTERFACE_MAP_BEGIN(RemoteInputStream)
NS_INTERFACE_MAP_ENTRY(nsIInputStream)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISeekableStream, IsSeekableStream())
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
NS_INTERFACE_MAP_END
namespace mozilla {
namespace dom {
namespace ipc {
// Explicit instantiation of both classes.
template class Blob<Parent>;
template class Blob<Child>;
} // namespace ipc
} // namespace dom
} // namespace mozilla

120
dom/ipc/Blob.h Normal file
View File

@ -0,0 +1,120 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set sw=4 ts=8 et 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_ipc_Blob_h
#define mozilla_dom_ipc_Blob_h
#include "mozilla/Attributes.h"
#include "mozilla/dom/PBlobChild.h"
#include "mozilla/dom/PBlobParent.h"
#include "mozilla/dom/PBlobStreamChild.h"
#include "mozilla/dom/PBlobStreamParent.h"
#include "mozilla/dom/PContentChild.h"
#include "mozilla/dom/PContentParent.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
class nsIDOMBlob;
namespace mozilla {
namespace dom {
namespace ipc {
enum ActorFlavorEnum
{
Parent = 0,
Child
};
template <ActorFlavorEnum>
struct BlobTraits
{ };
template <>
struct BlobTraits<Parent>
{
typedef mozilla::dom::PBlobParent BaseType;
typedef mozilla::dom::PBlobStreamParent StreamType;
typedef mozilla::dom::PContentParent ManagerType;
};
template <>
struct BlobTraits<Child>
{
typedef mozilla::dom::PBlobChild BaseType;
typedef mozilla::dom::PBlobStreamChild StreamType;
typedef mozilla::dom::PContentChild ManagerType;
};
template <ActorFlavorEnum>
class RemoteBlob;
template <ActorFlavorEnum ActorFlavor>
class Blob : public BlobTraits<ActorFlavor>::BaseType
{
public:
typedef typename BlobTraits<ActorFlavor>::BaseType BaseType;
typedef typename BlobTraits<ActorFlavor>::StreamType StreamType;
typedef typename BlobTraits<ActorFlavor>::ManagerType ManagerType;
typedef RemoteBlob<ActorFlavor> RemoteBlobType;
typedef mozilla::ipc::IProtocolManager<
mozilla::ipc::RPCChannel::RPCListener>::ActorDestroyReason
ActorDestroyReason;
typedef mozilla::dom::BlobConstructorParams BlobConstructorParams;
protected:
nsIDOMBlob* mBlob;
RemoteBlobType* mRemoteBlob;
bool mOwnsBlob;
public:
// This create function is called on the sending side.
static Blob*
Create(nsIDOMBlob* aBlob)
{
return new Blob(aBlob);
}
// This create function is called on the receiving side.
static Blob*
Create(const BlobConstructorParams& aParams);
already_AddRefed<nsIDOMBlob>
GetBlob();
void
NoteDyingRemoteBlob();
private:
// This constructor is called on the sending side.
Blob(nsIDOMBlob* aBlob);
// This constructor is called on the receiving side.
Blob(const BlobConstructorParams& aParams);
// These methods are only called by the IPDL message machinery.
virtual void
ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
virtual bool
RecvPBlobStreamConstructor(StreamType* aActor) MOZ_OVERRIDE;
virtual StreamType*
AllocPBlobStream() MOZ_OVERRIDE;
virtual bool
DeallocPBlobStream(StreamType* aActor) MOZ_OVERRIDE;
};
} // namespace ipc
typedef mozilla::dom::ipc::Blob<mozilla::dom::ipc::Child> BlobChild;
typedef mozilla::dom::ipc::Blob<mozilla::dom::ipc::Parent> BlobParent;
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_ipc_Blob_h

View File

@ -81,9 +81,13 @@
#include "nsIAccessibilityService.h"
#endif
#include "mozilla/dom/indexedDB/PIndexedDBChild.h"
#include "mozilla/dom/sms/SmsChild.h"
#include "mozilla/dom/devicestorage/DeviceStorageRequestChild.h"
#include "mozilla/dom/indexedDB/PIndexedDBChild.h"
#include "nsIDOMFile.h"
#include "nsIRemoteBlob.h"
#include "StructuredCloneUtils.h"
using namespace mozilla::docshell;
using namespace mozilla::dom::devicestorage;
@ -390,7 +394,7 @@ ContentChild::DeallocPMemoryReportRequest(PMemoryReportRequestChild* actor)
}
PCompositorChild*
ContentChild::AllocPCompositor(ipc::Transport* aTransport,
ContentChild::AllocPCompositor(mozilla::ipc::Transport* aTransport,
base::ProcessId aOtherProcess)
{
return CompositorChild::Create(aTransport, aOtherProcess);
@ -413,6 +417,71 @@ ContentChild::DeallocPBrowser(PBrowserChild* iframe)
return true;
}
PBlobChild*
ContentChild::AllocPBlob(const BlobConstructorParams& aParams)
{
return BlobChild::Create(aParams);
}
bool
ContentChild::DeallocPBlob(PBlobChild* aActor)
{
delete aActor;
return true;
}
BlobChild*
ContentChild::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
{
NS_ASSERTION(aBlob, "Null pointer!");
nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob);
if (remoteBlob) {
BlobChild* actor =
static_cast<BlobChild*>(static_cast<PBlobChild*>(remoteBlob->GetPBlob()));
NS_ASSERTION(actor, "Null actor?!");
return actor;
}
BlobConstructorParams params;
nsString contentType;
nsresult rv = aBlob->GetType(contentType);
NS_ENSURE_SUCCESS(rv, nullptr);
PRUint64 length;
rv = aBlob->GetSize(&length);
NS_ENSURE_SUCCESS(rv, nullptr);
nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
if (file) {
FileBlobConstructorParams fileParams;
rv = file->GetName(fileParams.name());
NS_ENSURE_SUCCESS(rv, nullptr);
fileParams.contentType() = contentType;
fileParams.length() = length;
params = fileParams;
} else {
NormalBlobConstructorParams blobParams;
blobParams.contentType() = contentType;
blobParams.length() = length;
params = blobParams;
}
BlobChild* actor = BlobChild::Create(aBlob);
NS_ENSURE_TRUE(actor, nullptr);
if (!SendPBlobConstructor(actor, params)) {
return nullptr;
}
return actor;
}
PCrashReporterChild*
ContentChild::AllocPCrashReporter(const mozilla::dom::NativeThreadId& id,
const PRUint32& processType)
@ -704,14 +773,30 @@ ContentChild::RecvNotifyVisited(const IPC::URI& aURI)
return true;
}
bool
ContentChild::RecvAsyncMessage(const nsString& aMsg, const nsString& aJSON)
ContentChild::RecvAsyncMessage(const nsString& aMsg,
const ClonedMessageData& aData)
{
nsRefPtr<nsFrameMessageManager> cpm = nsFrameMessageManager::sChildProcessManager;
if (cpm) {
const SerializedStructuredCloneBuffer& buffer = aData.data();
const InfallibleTArray<PBlobChild*>& blobChildList = aData.blobsChild();
StructuredCloneData cloneData;
cloneData.mData = buffer.data;
cloneData.mDataLength = buffer.dataLength;
if (!blobChildList.IsEmpty()) {
PRUint32 length = blobChildList.Length();
cloneData.mClosure.mBlobs.SetCapacity(length);
for (PRUint32 i = 0; i < length; ++i) {
BlobChild* blobChild = static_cast<BlobChild*>(blobChildList[i]);
MOZ_ASSERT(blobChild);
nsCOMPtr<nsIDOMBlob> blob = blobChild->GetBlob();
MOZ_ASSERT(blob);
cloneData.mClosure.mBlobs.AppendElement(blob);
}
}
cpm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(cpm.get()),
aMsg, false, aJSON, nullptr, nullptr);
aMsg, false, &cloneData, nullptr, nullptr);
}
return true;
}
@ -826,5 +911,20 @@ ContentChild::RecvLastPrivateDocShellDestroyed()
return true;
}
bool
ContentChild::RecvFilePathUpdate(const nsString& path, const nsCString& aReason)
{
// data strings will have the format of
// reason:path
nsString data;
CopyASCIItoUTF16(aReason, data);
data.Append(NS_LITERAL_STRING(":"));
data.Append(path);
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
obs->NotifyObservers(nullptr, "file-watcher-update", data.get());
return true;
}
} // namespace dom
} // namespace mozilla

View File

@ -9,11 +9,13 @@
#include "mozilla/Attributes.h"
#include "mozilla/dom/PContentChild.h"
#include "mozilla/dom/ipc/Blob.h"
#include "nsTArray.h"
#include "nsIConsoleListener.h"
struct ChromePackage;
class nsIDOMBlob;
class nsIObserver;
struct ResourceMapping;
struct OverrideMapping;
@ -30,10 +32,12 @@ class AlertObserver;
class PrefObserver;
class ConsoleListener;
class PStorageChild;
class ClonedMessageData;
class ContentChild : public PContentChild
{
typedef layers::PCompositorChild PCompositorChild;
typedef mozilla::dom::ClonedMessageData ClonedMessageData;
public:
ContentChild();
@ -59,7 +63,7 @@ public:
return mAppInfo;
}
PCompositorChild* AllocPCompositor(ipc::Transport* aTransport,
PCompositorChild* AllocPCompositor(mozilla::ipc::Transport* aTransport,
base::ProcessId aOtherProcess) MOZ_OVERRIDE;
virtual PBrowserChild* AllocPBrowser(const PRUint32& aChromeFlags,
@ -70,6 +74,9 @@ public:
virtual PDeviceStorageRequestChild* AllocPDeviceStorageRequest(const DeviceStorageParams&);
virtual bool DeallocPDeviceStorageRequest(PDeviceStorageRequestChild*);
virtual PBlobChild* AllocPBlob(const BlobConstructorParams& aParams);
virtual bool DeallocPBlob(PBlobChild*);
virtual PCrashReporterChild*
AllocPCrashReporter(const mozilla::dom::NativeThreadId& id,
const PRUint32& processType);
@ -134,7 +141,8 @@ public:
virtual bool RecvNotifyAlertsObserver(const nsCString& aType, const nsString& aData);
virtual bool RecvAsyncMessage(const nsString& aMsg, const nsString& aJSON);
virtual bool RecvAsyncMessage(const nsString& aMsg,
const ClonedMessageData& aData);
virtual bool RecvGeolocationUpdate(const GeoPosition& somewhere);
@ -154,6 +162,8 @@ public:
virtual bool RecvLastPrivateDocShellDestroyed();
virtual bool RecvFilePathUpdate(const nsString& path, const nsCString& reason);
#ifdef ANDROID
gfxIntSize GetScreenSize() { return mScreenSize; }
#endif
@ -164,6 +174,8 @@ public:
PRUint64 GetID() { return mID; }
BlobChild* GetOrCreateActorForBlob(nsIDOMBlob* aBlob);
private:
virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;

View File

@ -6,12 +6,13 @@
#include "base/basictypes.h"
#include "ContentParent.h"
#if defined(ANDROID) || defined(LINUX)
# include <sys/time.h>
# include <sys/resource.h>
#endif
#include "ContentParent.h"
#include "CrashReporterParent.h"
#include "History.h"
#include "IDBFactory.h"
@ -47,12 +48,14 @@
#include "nsIAlertsService.h"
#include "nsIClipboard.h"
#include "nsIConsoleService.h"
#include "nsIDOMFile.h"
#include "nsIDOMGeoGeolocation.h"
#include "nsIDOMWindow.h"
#include "nsIFilePicker.h"
#include "nsIMemoryReporter.h"
#include "nsIObserverService.h"
#include "nsIPresShell.h"
#include "nsIRemoteBlob.h"
#include "nsIScriptError.h"
#include "nsISupportsPrimitives.h"
#include "nsIWindowWatcher.h"
@ -63,6 +66,7 @@
#include "nsToolkitCompsCID.h"
#include "nsWidgetsCID.h"
#include "SandboxHal.h"
#include "StructuredCloneUtils.h"
#include "TabParent.h"
#ifdef ANDROID
@ -524,6 +528,8 @@ ContentParent::ContentParent(const nsAString& aAppManifestURL)
//Sending all information to content process
unused << SendAppInfo(version, buildID);
}
mFileWatchers.Init();
}
ContentParent::~ContentParent()
@ -760,6 +766,9 @@ ContentParent::Observe(nsISupports* aSubject,
const PRUnichar* aData)
{
if (!strcmp(aTopic, "xpcom-shutdown") && mSubprocess) {
mFileWatchers.Clear();
Close();
NS_ASSERTION(!mSubprocess, "Close should have nulled mSubprocess");
}
@ -827,7 +836,7 @@ ContentParent::Observe(nsISupports* aSubject,
}
PCompositorParent*
ContentParent::AllocPCompositor(ipc::Transport* aTransport,
ContentParent::AllocPCompositor(mozilla::ipc::Transport* aTransport,
base::ProcessId aOtherProcess)
{
return CompositorParent::Create(aTransport, aOtherProcess);
@ -866,6 +875,72 @@ ContentParent::DeallocPDeviceStorageRequest(PDeviceStorageRequestParent* doomed)
return true;
}
PBlobParent*
ContentParent::AllocPBlob(const BlobConstructorParams& aParams)
{
return BlobParent::Create(aParams);
}
bool
ContentParent::DeallocPBlob(PBlobParent* aActor)
{
delete aActor;
return true;
}
BlobParent*
ContentParent::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
{
NS_ASSERTION(aBlob, "Null pointer!");
nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob);
if (remoteBlob) {
BlobParent* actor =
static_cast<BlobParent*>(
static_cast<PBlobParent*>(remoteBlob->GetPBlob()));
NS_ASSERTION(actor, "Null actor?!");
return actor;
}
BlobConstructorParams params;
nsString contentType;
nsresult rv = aBlob->GetType(contentType);
NS_ENSURE_SUCCESS(rv, nullptr);
PRUint64 length;
rv = aBlob->GetSize(&length);
NS_ENSURE_SUCCESS(rv, nullptr);
nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
if (file) {
FileBlobConstructorParams fileParams;
rv = file->GetName(fileParams.name());
NS_ENSURE_SUCCESS(rv, nullptr);
fileParams.contentType() = contentType;
fileParams.length() = length;
params = fileParams;
} else {
NormalBlobConstructorParams blobParams;
blobParams.contentType() = contentType;
blobParams.length() = length;
params = blobParams;
}
BlobParent* actor = BlobParent::Create(aBlob);
NS_ENSURE_TRUE(actor, nullptr);
if (!SendPBlobConstructor(actor, params)) {
return nullptr;
}
return actor;
}
PCrashReporterParent*
ContentParent::AllocPCrashReporter(const NativeThreadId& tid,
const PRUint32& processType)
@ -930,7 +1005,7 @@ ContentParent::RecvPIndexedDBConstructor(PIndexedDBParent* aActor)
}
nsRefPtr<IDBFactory> factory;
nsresult rv = IDBFactory::Create(getter_AddRefs(factory));
nsresult rv = IDBFactory::Create(this, getter_AddRefs(factory));
NS_ENSURE_SUCCESS(rv, false);
NS_ASSERTION(factory, "This should never be null!");
@ -1291,24 +1366,59 @@ ContentParent::RecvShowAlertNotification(const nsString& aImageUrl, const nsStri
}
bool
ContentParent::RecvSyncMessage(const nsString& aMsg, const nsString& aJSON,
ContentParent::RecvSyncMessage(const nsString& aMsg,
const ClonedMessageData& aData,
InfallibleTArray<nsString>* aRetvals)
{
nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
if (ppm) {
const SerializedStructuredCloneBuffer& buffer = aData.data();
const InfallibleTArray<PBlobParent*>& blobParents = aData.blobsParent();
StructuredCloneData cloneData;
cloneData.mData = buffer.data;
cloneData.mDataLength = buffer.dataLength;
if (!blobParents.IsEmpty()) {
PRUint32 length = blobParents.Length();
cloneData.mClosure.mBlobs.SetCapacity(length);
for (PRUint32 index = 0; index < length; index++) {
BlobParent* blobParent = static_cast<BlobParent*>(blobParents[index]);
MOZ_ASSERT(blobParent);
nsCOMPtr<nsIDOMBlob> blob = blobParent->GetBlob();
MOZ_ASSERT(blob);
cloneData.mClosure.mBlobs.AppendElement(blob);
}
}
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
aMsg,true, aJSON, nullptr, aRetvals);
aMsg, true, &cloneData, nullptr, aRetvals);
}
return true;
}
bool
ContentParent::RecvAsyncMessage(const nsString& aMsg, const nsString& aJSON)
ContentParent::RecvAsyncMessage(const nsString& aMsg,
const ClonedMessageData& aData)
{
nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
if (ppm) {
const SerializedStructuredCloneBuffer& buffer = aData.data();
const InfallibleTArray<PBlobParent*>& blobParents = aData.blobsParent();
StructuredCloneData cloneData;
cloneData.mData = buffer.data;
cloneData.mDataLength = buffer.dataLength;
if (!blobParents.IsEmpty()) {
PRUint32 length = blobParents.Length();
cloneData.mClosure.mBlobs.SetCapacity(length);
for (PRUint32 index = 0; index < length; index++) {
BlobParent* blobParent = static_cast<BlobParent*>(blobParents[index]);
MOZ_ASSERT(blobParent);
nsCOMPtr<nsIDOMBlob> blob = blobParent->GetBlob();
MOZ_ASSERT(blob);
cloneData.mClosure.mBlobs.AppendElement(blob);
}
}
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
aMsg, false, aJSON, nullptr, nullptr);
aMsg, false, &cloneData, nullptr, nullptr);
}
return true;
}
@ -1402,5 +1512,64 @@ ContentParent::RecvPrivateDocShellsExist(const bool& aExist)
return true;
}
bool
ContentParent::RecvAddFileWatch(const nsString& root)
{
nsRefPtr<WatchedFile> f;
if (mFileWatchers.Get(root, getter_AddRefs(f))) {
f->mUsageCount++;
return true;
}
f = new WatchedFile(this, root);
mFileWatchers.Put(root, f);
f->Watch();
return true;
}
bool
ContentParent::RecvRemoveFileWatch(const nsString& root)
{
nsRefPtr<WatchedFile> f;
bool result = mFileWatchers.Get(root, getter_AddRefs(f));
if (!result) {
return true;
}
if (!f)
return true;
f->mUsageCount--;
if (f->mUsageCount > 0) {
return true;
}
f->Unwatch();
mFileWatchers.Remove(root);
return true;
}
NS_IMPL_ISUPPORTS1(ContentParent::WatchedFile, nsIFileUpdateListener)
nsresult
ContentParent::WatchedFile::Update(const char* aReason, nsIFile* aFile)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
nsString path;
aFile->GetPath(path);
unused << mParent->SendFilePathUpdate(path, nsDependentCString(aReason));
#ifdef DEBUG
nsCString cpath;
aFile->GetNativePath(cpath);
printf("ContentParent::WatchedFile::Update: %s -- %s\n", cpath.get(), aReason);
#endif
return NS_OK;
}
} // namespace dom
} // namespace mozilla

View File

@ -12,6 +12,7 @@
#include "mozilla/dom/PContentParent.h"
#include "mozilla/dom/PMemoryReportRequestParent.h"
#include "mozilla/ipc/GeckoChildProcessHost.h"
#include "mozilla/dom/ipc/Blob.h"
#include "nsIObserver.h"
#include "nsIThreadInternal.h"
@ -21,8 +22,12 @@
#include "nsIMemoryReporter.h"
#include "nsCOMArray.h"
#include "nsDataHashtable.h"
#include "nsInterfaceHashtable.h"
#include "nsHashKeys.h"
class nsFrameMessageManager;
class nsIDOMBlob;
namespace mozilla {
namespace ipc {
@ -37,6 +42,7 @@ namespace dom {
class TabParent;
class PStorageParent;
class ClonedMessageData;
class ContentParent : public PContentParent
, public nsIObserver
@ -47,6 +53,7 @@ private:
typedef mozilla::ipc::GeckoChildProcessHost GeckoChildProcessHost;
typedef mozilla::ipc::TestShellParent TestShellParent;
typedef mozilla::layers::PCompositorParent PCompositorParent;
typedef mozilla::dom::ClonedMessageData ClonedMessageData;
public:
static ContentParent* GetNewOrUsed();
@ -97,6 +104,8 @@ public:
return mSendPermissionUpdates;
}
BlobParent* GetOrCreateActorForBlob(nsIDOMBlob* aBlob);
protected:
void OnChannelConnected(int32 pid);
virtual void ActorDestroy(ActorDestroyReason why);
@ -130,7 +139,7 @@ private:
*/
void ShutDown();
PCompositorParent* AllocPCompositor(ipc::Transport* aTransport,
PCompositorParent* AllocPCompositor(mozilla::ipc::Transport* aTransport,
base::ProcessId aOtherProcess) MOZ_OVERRIDE;
virtual PBrowserParent* AllocPBrowser(const PRUint32& aChromeFlags, const bool& aIsBrowserElement, const PRUint32& aAppId);
@ -139,6 +148,9 @@ private:
virtual PDeviceStorageRequestParent* AllocPDeviceStorageRequest(const DeviceStorageParams&);
virtual bool DeallocPDeviceStorageRequest(PDeviceStorageRequestParent*);
virtual PBlobParent* AllocPBlob(const BlobConstructorParams& aParams);
virtual bool DeallocPBlob(PBlobParent*);
virtual PCrashReporterParent* AllocPCrashReporter(const NativeThreadId& tid,
const PRUint32& processType);
virtual bool DeallocPCrashReporter(PCrashReporterParent* crashreporter);
@ -226,9 +238,11 @@ private:
virtual bool RecvLoadURIExternal(const IPC::URI& uri);
virtual bool RecvSyncMessage(const nsString& aMsg, const nsString& aJSON,
virtual bool RecvSyncMessage(const nsString& aMsg,
const ClonedMessageData& aData,
InfallibleTArray<nsString>* aRetvals);
virtual bool RecvAsyncMessage(const nsString& aMsg, const nsString& aJSON);
virtual bool RecvAsyncMessage(const nsString& aMsg,
const ClonedMessageData& aData);
virtual bool RecvAddGeolocationListener();
virtual bool RecvRemoveGeolocationListener();
@ -243,6 +257,10 @@ private:
const nsCString& aCategory);
virtual bool RecvPrivateDocShellsExist(const bool& aExist);
virtual bool RecvAddFileWatch(const nsString& root);
virtual bool RecvRemoveFileWatch(const nsString& root);
GeckoChildProcessHost* mSubprocess;
PRInt32 mGeolocationWatchID;
@ -261,6 +279,34 @@ private:
const nsString mAppManifestURL;
nsRefPtr<nsFrameMessageManager> mMessageManager;
class WatchedFile : public nsIFileUpdateListener {
public:
WatchedFile(ContentParent* aParent, const nsString& aPath)
: mParent(aParent)
, mUsageCount(1)
{
NS_NewLocalFile(aPath, false, getter_AddRefs(mFile));
}
NS_DECL_ISUPPORTS
NS_DECL_NSIFILEUPDATELISTENER
void Watch() {
mFile->Watch(this);
}
void Unwatch() {
mFile->Watch(this);
}
nsRefPtr<ContentParent> mParent;
PRInt32 mUsageCount;
nsCOMPtr<nsIFile> mFile;
};
// This is a cache of all of the registered file watchers.
nsInterfaceHashtable<nsStringHashKey, WatchedFile> mFileWatchers;
friend class CrashReporterParent;
};

21
dom/ipc/DOMTypes.ipdlh Normal file
View File

@ -0,0 +1,21 @@
/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8 -*- */
/* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
/* 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 protocol PBlob;
using mozilla::SerializedStructuredCloneBuffer;
namespace mozilla {
namespace dom {
struct ClonedMessageData
{
SerializedStructuredCloneBuffer data;
PBlob[] blobs;
};
} // namespace dom
} // namespace mozilla

View File

@ -21,7 +21,10 @@ endif
EXPORTS = PCOMContentPermissionRequestChild.h
EXPORTS_NAMESPACES = mozilla/dom
EXPORTS_NAMESPACES = \
mozilla/dom \
mozilla/dom/ipc \
$(NULL)
EXPORTS_mozilla/dom = \
ContentChild.h \
@ -29,17 +32,25 @@ EXPORTS_mozilla/dom = \
ContentProcess.h \
CrashReporterChild.h \
CrashReporterParent.h \
StructuredCloneUtils.h \
TabParent.h \
TabChild.h \
TabMessageUtils.h \
$(NULL)
EXPORTS_mozilla/dom/ipc = \
Blob.h \
nsIRemoteBlob.h \
$(NULL)
CPPSRCS = \
Blob.cpp \
ContentProcess.cpp \
ContentParent.cpp \
ContentChild.cpp \
CrashReporterParent.cpp \
CrashReporterChild.cpp \
StructuredCloneUtils.cpp \
TabParent.cpp \
TabChild.cpp \
TabMessageUtils.cpp \

23
dom/ipc/PBlob.ipdl Normal file
View File

@ -0,0 +1,23 @@
/* 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 protocol PBlobStream;
include protocol PContent;
namespace mozilla {
namespace dom {
protocol PBlob
{
manager PContent;
manages PBlobStream;
both:
__delete__();
PBlobStream();
};
} // namespace dom
} // namespace mozilla

23
dom/ipc/PBlobStream.ipdl Normal file
View File

@ -0,0 +1,23 @@
/* 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 protocol PBlob;
include "mozilla/net/NeckoMessageUtils.h";
using IPC::InputStream;
namespace mozilla {
namespace dom {
protocol PBlobStream
{
manager PBlob;
both:
__delete__(InputStream stream);
};
} // namespace dom
} // namespace mozilla

View File

@ -5,6 +5,7 @@
* 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 protocol PBlob;
include protocol PContent;
include protocol PContentDialog;
include protocol PDocumentRenderer;
@ -19,6 +20,8 @@ include "mozilla/dom/TabMessageUtils.h";
include "mozilla/layout/RenderFrameUtils.h";
include "mozilla/net/NeckoMessageUtils.h";
include DOMTypes;
using IPC::URI;
using gfxMatrix;
using gfxSize;
@ -56,7 +59,7 @@ rpc protocol PBrowser
manages PIndexedDB;
both:
AsyncMessage(nsString aMessage, nsString aJSON);
AsyncMessage(nsString aMessage, ClonedMessageData aData);
parent:
/**
@ -69,7 +72,7 @@ parent:
rpc CreateWindow() returns (PBrowser window);
sync SyncMessage(nsString aMessage, nsString aJSON)
sync SyncMessage(nsString aMessage, ClonedMessageData aData)
returns (nsString[] retval);
/**
@ -339,4 +342,4 @@ state DYING:
};
}
}
}

View File

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
include protocol PAudio;
include protocol PBlob;
include protocol PBrowser;
include protocol PCompositor;
include protocol PCrashReporter;
@ -25,6 +26,8 @@ include "mozilla/dom/TabMessageUtils.h";
include "nsGeoPositionIPCSerialiser.h";
include "PPrefTuple.h";
include DOMTypes;
using GeoPosition;
using PrefTuple;
@ -34,6 +37,7 @@ using OverrideMapping;
using IPC::URI;
using IPC::Permission;
using mozilla::null_t;
using mozilla::void_t;
using mozilla::dom::NativeThreadId;
using gfxIntSize;
@ -96,11 +100,41 @@ union DeviceStorageParams
DeviceStorageDeleteParams;
DeviceStorageEnumerationParams;
};
struct NormalBlobConstructorParams
{
nsString contentType;
uint64_t length;
};
struct FileBlobConstructorParams
{
nsString name;
nsString contentType;
uint64_t length;
};
struct SlicedBlobConstructorParams
{
PBlob source;
uint64_t begin;
uint64_t end;
nsString contentType;
};
union BlobConstructorParams
{
NormalBlobConstructorParams;
FileBlobConstructorParams;
SlicedBlobConstructorParams;
};
rpc protocol PContent
{
parent opens PCompositor;
manages PAudio;
manages PBlob;
manages PBrowser;
manages PCrashReporter;
manages PDeviceStorageRequest;
@ -122,6 +156,8 @@ both:
// as part of ContentParent::CreateTab.
async PBrowser(PRUint32 chromeFlags, bool isBrowserElement, PRUint32 appId);
async PBlob(BlobConstructorParams params);
child:
PMemoryReportRequest();
@ -163,6 +199,8 @@ child:
// Notify child that last-pb-context-exited notification was observed
LastPrivateDocShellDestroyed();
FilePathUpdate(nsString filepath, nsCString reasons);
parent:
PAudio(PRInt32 aNumChannels, PRInt32 aRate, PRInt32 aFormat);
@ -199,7 +237,7 @@ parent:
sync ReadFontList() returns (FontListEntry[] retValue);
sync SyncMessage(nsString aMessage, nsString aJSON)
sync SyncMessage(nsString aMessage, ClonedMessageData aData)
returns (nsString[] retval);
ShowAlertNotification(nsString imageUrl,
@ -245,9 +283,11 @@ parent:
// Notify the parent of the presence or absence of private docshells
PrivateDocShellsExist(bool aExist);
both:
AsyncMessage(nsString aMessage, nsString aJSON);
AddFileWatch(nsString filepath);
RemoveFileWatch(nsString filepath);
both:
AsyncMessage(nsString aMessage, ClonedMessageData aData);
};
}

View File

@ -0,0 +1,187 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set sw=4 ts=8 et tw=80 : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "StructuredCloneUtils.h"
#include "nsIDOMFile.h"
#include "nsIDOMDOMException.h"
#include "nsIMutable.h"
#include "nsIXPConnect.h"
#include "nsContentUtils.h"
#include "nsJSEnvironment.h"
#include "nsThreadUtils.h"
#include "StructuredCloneTags.h"
using namespace mozilla::dom;
namespace {
void
Error(JSContext* aCx, uint32_t aErrorId)
{
MOZ_ASSERT(NS_IsMainThread());
NS_DOMStructuredCloneError(aCx, aErrorId);
}
JSObject*
Read(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag,
uint32_t aData, void* aClosure)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aClosure);
StructuredCloneClosure* closure =
static_cast<StructuredCloneClosure*>(aClosure);
if (aTag == SCTAG_DOM_FILE) {
MOZ_ASSERT(aData < closure->mBlobs.Length());
nsCOMPtr<nsIDOMFile> file = do_QueryInterface(closure->mBlobs[aData]);
MOZ_ASSERT(file);
#ifdef DEBUG
{
// File should not be mutable.
nsCOMPtr<nsIMutable> mutableFile = do_QueryInterface(file);
bool isMutable;
if (NS_FAILED(mutableFile->GetMutable(&isMutable))) {
MOZ_NOT_REACHED("GetMutable failed!");
}
else {
MOZ_ASSERT(!isMutable);
}
}
#endif
jsval wrappedFile;
nsresult rv =
nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), file,
&NS_GET_IID(nsIDOMFile), &wrappedFile);
if (NS_FAILED(rv)) {
Error(aCx, nsIDOMDOMException::DATA_CLONE_ERR);
return nullptr;
}
return &wrappedFile.toObject();
}
if (aTag == SCTAG_DOM_BLOB) {
MOZ_ASSERT(aData < closure->mBlobs.Length());
nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(closure->mBlobs[aData]);
MOZ_ASSERT(blob);
#ifdef DEBUG
{
// Blob should not be mutable.
nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(blob);
bool isMutable;
if (NS_FAILED(mutableBlob->GetMutable(&isMutable))) {
MOZ_NOT_REACHED("GetMutable failed!");
}
else {
MOZ_ASSERT(!isMutable);
}
}
#endif
jsval wrappedBlob;
nsresult rv =
nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), blob,
&NS_GET_IID(nsIDOMBlob), &wrappedBlob);
if (NS_FAILED(rv)) {
Error(aCx, nsIDOMDOMException::DATA_CLONE_ERR);
return nullptr;
}
return &wrappedBlob.toObject();
}
return NS_DOMReadStructuredClone(aCx, aReader, aTag, aData, nullptr);
}
JSBool
Write(JSContext* aCx, JSStructuredCloneWriter* aWriter, JSObject* aObj,
void* aClosure)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aClosure);
StructuredCloneClosure* closure =
static_cast<StructuredCloneClosure*>(aClosure);
// See if this is a wrapped native.
nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative;
nsContentUtils::XPConnect()->
GetWrappedNativeOfJSObject(aCx, aObj, getter_AddRefs(wrappedNative));
if (wrappedNative) {
// Get the raw nsISupports out of it.
nsISupports* wrappedObject = wrappedNative->Native();
MOZ_ASSERT(wrappedObject);
// See if the wrapped native is a nsIDOMFile.
nsCOMPtr<nsIDOMFile> file = do_QueryInterface(wrappedObject);
if (file) {
nsCOMPtr<nsIMutable> mutableFile = do_QueryInterface(file);
if (mutableFile &&
NS_SUCCEEDED(mutableFile->SetMutable(false)) &&
JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILE,
closure->mBlobs.Length())) {
closure->mBlobs.AppendElement(file);
return true;
}
}
// See if the wrapped native is a nsIDOMBlob.
nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(wrappedObject);
if (blob) {
nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(blob);
if (mutableBlob &&
NS_SUCCEEDED(mutableBlob->SetMutable(false)) &&
JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB,
closure->mBlobs.Length())) {
closure->mBlobs.AppendElement(blob);
return true;
}
}
}
return NS_DOMWriteStructuredClone(aCx, aWriter, aObj, nullptr);
}
JSStructuredCloneCallbacks gCallbacks = {
Read,
Write,
Error
};
} // anonymous namespace
namespace mozilla {
namespace dom {
bool
ReadStructuredClone(JSContext* aCx, const uint64_t* aData, size_t aDataLength,
const StructuredCloneClosure& aClosure, JS::Value* aClone)
{
void* closure = &const_cast<StructuredCloneClosure&>(aClosure);
return !!JS_ReadStructuredClone(aCx, aData, aDataLength,
JS_STRUCTURED_CLONE_VERSION, aClone,
&gCallbacks, closure);
}
bool
WriteStructuredClone(JSContext* aCx, const JS::Value& aSource,
JSAutoStructuredCloneBuffer& aBuffer,
StructuredCloneClosure& aClosure)
{
return aBuffer.write(aCx, aSource, &gCallbacks, &aClosure);
}
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,56 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set sw=4 ts=8 et 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_StructuredCloneUtils_h
#define mozilla_dom_StructuredCloneUtils_h
#include "jsapi.h"
#include "nsCOMPtr.h"
#include "nsTArray.h"
#include "nsIDOMFile.h"
namespace mozilla {
struct SerializedStructuredCloneBuffer;
namespace dom {
struct
StructuredCloneClosure
{
nsTArray<nsCOMPtr<nsIDOMBlob> > mBlobs;
};
struct
StructuredCloneData
{
StructuredCloneData() : mData(nullptr), mDataLength(0) {}
uint64_t* mData;
size_t mDataLength;
StructuredCloneClosure mClosure;
};
bool
ReadStructuredClone(JSContext* aCx, const uint64_t* aData, size_t aDataLength,
const StructuredCloneClosure& aClosure, JS::Value* aClone);
inline bool
ReadStructuredClone(JSContext* aCx, const StructuredCloneData& aData,
JS::Value* aClone)
{
return ReadStructuredClone(aCx, aData.mData, aData.mDataLength,
aData.mClosure, aClone);
}
bool
WriteStructuredClone(JSContext* aCx, const JS::Value& aSource,
JSAutoStructuredCloneBuffer& aBuffer,
StructuredCloneClosure& aClosure);
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_StructuredCloneUtils_h

View File

@ -6,7 +6,11 @@
#include "base/basictypes.h"
#include "TabChild.h"
#include "BasicLayers.h"
#include "Blob.h"
#include "ContentChild.h"
#include "IndexedDBChild.h"
#include "mozilla/IntentionalCrash.h"
#include "mozilla/docshell/OfflineCacheUpdateChild.h"
@ -58,9 +62,10 @@
#include "nsThreadUtils.h"
#include "nsWeakReference.h"
#include "PCOMContentPermissionRequestChild.h"
#include "TabChild.h"
#include "StructuredCloneUtils.h"
#include "xpcpublic.h"
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::ipc;
using namespace mozilla::layers;
@ -646,6 +651,9 @@ TabChild::RecvUpdateFrame(const nsIntRect& aDisplayPort,
const gfxSize& aResolution,
const nsIntRect& aScreenSize)
{
if (!mCx || !mTabChildGlobal) {
return true;
}
nsCString data;
data += nsPrintfCString("{ \"x\" : %d", aScrollOffset.x);
data += nsPrintfCString(", \"y\" : %d", aScrollOffset.y);
@ -665,10 +673,25 @@ TabChild::RecvUpdateFrame(const nsIntRect& aDisplayPort,
data += nsPrintfCString(" }");
data += nsPrintfCString(" }");
jsval json = JSVAL_NULL;
StructuredCloneData cloneData;
JSAutoStructuredCloneBuffer buffer;
if (JS_ParseJSON(mCx,
static_cast<const jschar*>(NS_ConvertUTF8toUTF16(data).get()),
data.Length(),
&json)) {
WriteStructuredClone(mCx, json, buffer, cloneData.mClosure);
}
nsFrameScriptCx cx(static_cast<nsIWebBrowserChrome*>(this), this);
// Let the BrowserElementScrolling helper (if it exists) for this
// content manipulate the frame state.
return RecvAsyncMessage(NS_LITERAL_STRING("Viewport:Change"),
NS_ConvertUTF8toUTF16(data));
nsRefPtr<nsFrameMessageManager> mm =
static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get());
mm->ReceiveMessage(static_cast<nsIDOMEventTarget*>(mTabChildGlobal),
NS_LITERAL_STRING("Viewport:Change"), false,
&cloneData, nullptr, nullptr);
return true;
}
bool
@ -958,14 +981,36 @@ TabChild::RecvLoadRemoteScript(const nsString& aURL)
bool
TabChild::RecvAsyncMessage(const nsString& aMessage,
const nsString& aJSON)
const ClonedMessageData& aData)
{
if (mTabChildGlobal) {
nsFrameScriptCx cx(static_cast<nsIWebBrowserChrome*>(this), this);
const SerializedStructuredCloneBuffer& buffer = aData.data();
const InfallibleTArray<PBlobChild*>& blobChildList = aData.blobsChild();
StructuredCloneData cloneData;
cloneData.mData = buffer.data;
cloneData.mDataLength = buffer.dataLength;
if (!blobChildList.IsEmpty()) {
PRUint32 length = blobChildList.Length();
cloneData.mClosure.mBlobs.SetCapacity(length);
for (PRUint32 i = 0; i < length; ++i) {
BlobChild* blobChild = static_cast<BlobChild*>(blobChildList[i]);
MOZ_ASSERT(blobChild);
nsCOMPtr<nsIDOMBlob> blob = blobChild->GetBlob();
MOZ_ASSERT(blob);
cloneData.mClosure.mBlobs.AppendElement(blob);
}
}
nsRefPtr<nsFrameMessageManager> mm =
static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get());
mm->ReceiveMessage(static_cast<nsIDOMEventTarget*>(mTabChildGlobal),
aMessage, false, aJSON, nullptr, nullptr);
aMessage, false, &cloneData, nullptr, nullptr);
}
return true;
}
@ -1184,23 +1229,62 @@ TabChild::DeallocPIndexedDB(PIndexedDBChild* aActor)
static bool
SendSyncMessageToParent(void* aCallbackData,
const nsAString& aMessage,
const nsAString& aJSON,
const StructuredCloneData& aData,
InfallibleTArray<nsString>* aJSONRetVal)
{
return static_cast<TabChild*>(aCallbackData)->
SendSyncMessage(nsString(aMessage), nsString(aJSON),
aJSONRetVal);
TabChild* tabChild = static_cast<TabChild*>(aCallbackData);
ContentChild* cc = static_cast<ContentChild*>(tabChild->Manager());
ClonedMessageData data;
SerializedStructuredCloneBuffer& buffer = data.data();
buffer.data = aData.mData;
buffer.dataLength = aData.mDataLength;
const nsTArray<nsCOMPtr<nsIDOMBlob> >& blobs = aData.mClosure.mBlobs;
if (!blobs.IsEmpty()) {
InfallibleTArray<PBlobChild*>& blobChildList = data.blobsChild();
PRUint32 length = blobs.Length();
blobChildList.SetCapacity(length);
for (PRUint32 i = 0; i < length; ++i) {
BlobChild* blobChild = cc->GetOrCreateActorForBlob(blobs[i]);
if (!blobChild) {
return false;
}
blobChildList.AppendElement(blobChild);
}
}
return tabChild->SendSyncMessage(nsString(aMessage), data, aJSONRetVal);
}
static bool
SendAsyncMessageToParent(void* aCallbackData,
const nsAString& aMessage,
const nsAString& aJSON)
const StructuredCloneData& aData)
{
return static_cast<TabChild*>(aCallbackData)->
SendAsyncMessage(nsString(aMessage), nsString(aJSON));
TabChild* tabChild = static_cast<TabChild*>(aCallbackData);
ContentChild* cc = static_cast<ContentChild*>(tabChild->Manager());
ClonedMessageData data;
SerializedStructuredCloneBuffer& buffer = data.data();
buffer.data = aData.mData;
buffer.dataLength = aData.mDataLength;
const nsTArray<nsCOMPtr<nsIDOMBlob> >& blobs = aData.mClosure.mBlobs;
if (!blobs.IsEmpty()) {
InfallibleTArray<PBlobChild*>& blobChildList = data.blobsChild();
PRUint32 length = blobs.Length();
blobChildList.SetCapacity(length);
for (PRUint32 i = 0; i < length; ++i) {
BlobChild* blobChild = cc->GetOrCreateActorForBlob(blobs[i]);
if (!blobChild) {
return false;
}
blobChildList.AppendElement(blobChild);
}
}
return tabChild->SendAsyncMessage(nsString(aMessage), data);
}
TabChildGlobal::TabChildGlobal(TabChild* aTabChild)
: mTabChild(aTabChild)
{

View File

@ -59,6 +59,7 @@ namespace dom {
class TabChild;
class PContentDialogChild;
class ClonedMessageData;
class TabChildGlobal : public nsDOMEventTargetHelper,
public nsIContentFrameMessageManager,
@ -142,6 +143,7 @@ class TabChild : public PBrowserChild,
public nsITabChild
{
typedef mozilla::layout::RenderFrameChild RenderFrameChild;
typedef mozilla::dom::ClonedMessageData ClonedMessageData;
public:
/**
@ -196,7 +198,7 @@ public:
virtual bool RecvActivateFrameEvent(const nsString& aType, const bool& capture);
virtual bool RecvLoadRemoteScript(const nsString& aURL);
virtual bool RecvAsyncMessage(const nsString& aMessage,
const nsString& aJSON);
const ClonedMessageData& aData);
virtual PDocumentRendererChild*
AllocPDocumentRenderer(const nsRect& documentRect, const gfxMatrix& transform,

View File

@ -6,6 +6,9 @@
#include "base/basictypes.h"
#include "TabParent.h"
#include "Blob.h"
#include "IDBFactory.h"
#include "IndexedDBParent.h"
#include "mozilla/BrowserElementParent.h"
@ -42,8 +45,8 @@
#include "nsSerializationHelper.h"
#include "nsServiceManagerUtils.h"
#include "nsThreadUtils.h"
#include "StructuredCloneUtils.h"
#include "TabChild.h"
#include "TabParent.h"
using namespace mozilla::dom;
using namespace mozilla::ipc;
@ -344,17 +347,51 @@ bool TabParent::SendRealTouchEvent(nsTouchEvent& event)
bool
TabParent::RecvSyncMessage(const nsString& aMessage,
const nsString& aJSON,
const ClonedMessageData& aData,
InfallibleTArray<nsString>* aJSONRetVal)
{
return ReceiveMessage(aMessage, true, aJSON, aJSONRetVal);
const SerializedStructuredCloneBuffer& buffer = aData.data();
const InfallibleTArray<PBlobParent*>& blobParents = aData.blobsParent();
StructuredCloneData cloneData;
cloneData.mData = buffer.data;
cloneData.mDataLength = buffer.dataLength;
if (!blobParents.IsEmpty()) {
PRUint32 length = blobParents.Length();
cloneData.mClosure.mBlobs.SetCapacity(length);
for (PRUint32 i = 0; i < length; ++i) {
BlobParent* blobParent = static_cast<BlobParent*>(blobParents[i]);
MOZ_ASSERT(blobParent);
nsCOMPtr<nsIDOMBlob> blob = blobParent->GetBlob();
MOZ_ASSERT(blob);
cloneData.mClosure.mBlobs.AppendElement(blob);
}
}
return ReceiveMessage(aMessage, true, &cloneData, aJSONRetVal);
}
bool
TabParent::RecvAsyncMessage(const nsString& aMessage,
const nsString& aJSON)
const ClonedMessageData& aData)
{
return ReceiveMessage(aMessage, false, aJSON, nullptr);
const SerializedStructuredCloneBuffer& buffer = aData.data();
const InfallibleTArray<PBlobParent*>& blobParents = aData.blobsParent();
StructuredCloneData cloneData;
cloneData.mData = buffer.data;
cloneData.mDataLength = buffer.dataLength;
if (!blobParents.IsEmpty()) {
PRUint32 length = blobParents.Length();
cloneData.mClosure.mBlobs.SetCapacity(length);
for (PRUint32 i = 0; i < length; ++i) {
BlobParent* blobParent = static_cast<BlobParent*>(blobParents[i]);
MOZ_ASSERT(blobParent);
nsCOMPtr<nsIDOMBlob> blob = blobParent->GetBlob();
MOZ_ASSERT(blob);
cloneData.mClosure.mBlobs.AppendElement(blob);
}
}
return ReceiveMessage(aMessage, false, &cloneData, nullptr);
}
bool
@ -697,7 +734,7 @@ TabParent::RecvGetWidgetNativeData(WindowsHandle* aValue)
bool
TabParent::ReceiveMessage(const nsString& aMessage,
bool aSync,
const nsString& aJSON,
const StructuredCloneData* aCloneData,
InfallibleTArray<nsString>* aJSONRetVal)
{
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
@ -717,7 +754,7 @@ TabParent::ReceiveMessage(const nsString& aMessage,
manager->ReceiveMessage(mFrameElement,
aMessage,
aSync,
aJSON,
aCloneData,
objectsArray,
aJSONRetVal);
}
@ -758,9 +795,13 @@ TabParent::RecvPIndexedDBConstructor(PIndexedDBParent* aActor,
nsCOMPtr<nsPIDOMWindow> window = doc->GetInnerWindow();
NS_ENSURE_TRUE(window, false);
ContentParent* contentParent = static_cast<ContentParent*>(Manager());
NS_ASSERTION(contentParent, "Null manager?!");
nsRefPtr<IDBFactory> factory;
nsresult rv =
IDBFactory::Create(window, aASCIIOrigin, getter_AddRefs(factory));
IDBFactory::Create(window, aASCIIOrigin, contentParent,
getter_AddRefs(factory));
NS_ENSURE_SUCCESS(rv, false);
if (!factory) {

View File

@ -40,6 +40,9 @@ class RenderFrameParent;
namespace dom {
class ClonedMessageData;
struct StructuredCloneData;
class ContentDialogParent : public PContentDialogParent {};
class TabParent : public PBrowserParent
@ -47,6 +50,8 @@ class TabParent : public PBrowserParent
, public nsIAuthPromptProvider
, public nsISecureBrowserUI
{
typedef mozilla::dom::ClonedMessageData ClonedMessageData;
public:
TabParent();
virtual ~TabParent();
@ -68,10 +73,10 @@ public:
bool* aOutWindowOpened);
virtual bool AnswerCreateWindow(PBrowserParent** retval);
virtual bool RecvSyncMessage(const nsString& aMessage,
const nsString& aJSON,
const ClonedMessageData& aData,
InfallibleTArray<nsString>* aJSONRetVal);
virtual bool RecvAsyncMessage(const nsString& aMessage,
const nsString& aJSON);
const ClonedMessageData& aData);
virtual bool RecvNotifyIMEFocus(const bool& aFocus,
nsIMEUpdatePreference* aPreference,
PRUint32* aSeqno);
@ -172,7 +177,7 @@ public:
protected:
bool ReceiveMessage(const nsString& aMessage,
bool aSync,
const nsString& aJSON,
const StructuredCloneData* aCloneData,
InfallibleTArray<nsString>* aJSONRetVal = nullptr);
virtual bool Recv__delete__() MOZ_OVERRIDE;

View File

@ -3,7 +3,10 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
IPDLSRCS = \
DOMTypes.ipdlh \
PAudio.ipdl \
PBlob.ipdl \
PBlobStream.ipdl \
PBrowser.ipdl \
PContent.ipdl \
PContentDialog.ipdl \

28
dom/ipc/nsIRemoteBlob.h Normal file
View File

@ -0,0 +1,28 @@
/* 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_ipc_nsIRemoteBlob_h
#define mozilla_dom_ipc_nsIRemoteBlob_h
#include "nsISupports.h"
#ifndef NS_NO_VTABLE
#define NS_NO_VTABLE
#endif
#define NS_IREMOTEBLOB_IID \
{0x74ce3cdd, 0xbfc9, 0x4edb, {0x98, 0x26, 0x50, 0xcf, 0x00, 0x26, 0x58, 0x70}}
class NS_NO_VTABLE nsIRemoteBlob : public nsISupports
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IREMOTEBLOB_IID)
// This will either return a PBlobChild or PBlobParent.
virtual void* GetPBlob() = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIRemoteBlob, NS_IREMOTEBLOB_IID)
#endif // mozilla_dom_ipc_nsIRemoteBlob_h

Some files were not shown because too many files have changed in this diff Show More