diff --git a/dom/indexedDB/FileSnapshot.cpp b/dom/indexedDB/FileSnapshot.cpp
index e303ae39628..519ffe564f8 100644
--- a/dom/indexedDB/FileSnapshot.cpp
+++ b/dom/indexedDB/FileSnapshot.cpp
@@ -86,7 +86,7 @@ FileImplSnapshot::AssertSanity()
#endif // DEBUG
-NS_IMPL_ISUPPORTS_INHERITED0(FileImplSnapshot, FileImpl)
+NS_IMPL_ISUPPORTS_INHERITED(FileImplSnapshot, FileImpl, PIFileImplSnapshot)
void
FileImplSnapshot::Unlink()
diff --git a/dom/indexedDB/FileSnapshot.h b/dom/indexedDB/FileSnapshot.h
index 050dc3708d6..e79408f70cd 100644
--- a/dom/indexedDB/FileSnapshot.h
+++ b/dom/indexedDB/FileSnapshot.h
@@ -11,6 +11,18 @@
#include "mozilla/dom/File.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
+#include "nsISupports.h"
+
+#define FILEIMPLSNAPSHOT_IID \
+ {0x0dfc11b1, 0x75d3, 0x473b, {0x8c, 0x67, 0xb7, 0x23, 0xf4, 0x67, 0xd6, 0x73}}
+
+class PIFileImplSnapshot : public nsISupports
+{
+public:
+ NS_DECLARE_STATIC_IID_ACCESSOR(FILEIMPLSNAPSHOT_IID)
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(PIFileImplSnapshot, FILEIMPLSNAPSHOT_IID)
namespace mozilla {
namespace dom {
@@ -23,6 +35,7 @@ class IDBFileHandle;
class FileImplSnapshot MOZ_FINAL
: public FileImplBase
+ , public PIFileImplSnapshot
{
typedef mozilla::dom::MetadataParameters MetadataParameters;
diff --git a/dom/indexedDB/test/mochitest.ini b/dom/indexedDB/test/mochitest.ini
index c4b85293fe4..e049e024c9f 100644
--- a/dom/indexedDB/test/mochitest.ini
+++ b/dom/indexedDB/test/mochitest.ini
@@ -19,6 +19,7 @@ support-files =
unit/test_advance.js
unit/test_autoIncrement.js
unit/test_autoIncrement_indexes.js
+ unit/test_blob_file_backed.js
unit/test_blocked_order.js
unit/test_clear.js
unit/test_complex_keyPaths.js
@@ -111,6 +112,9 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_blob_archive.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
+[test_blob_file_backed.html]
+# This test can only run in the main process.
+skip-if = buildapp == 'b2g' || buildapp == 'mulet' || e10s
[test_blob_simple.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_blob_worker_crash.html]
diff --git a/dom/indexedDB/test/test_blob_file_backed.html b/dom/indexedDB/test/test_blob_file_backed.html
new file mode 100644
index 00000000000..3c3f103d6e0
--- /dev/null
+++ b/dom/indexedDB/test/test_blob_file_backed.html
@@ -0,0 +1,18 @@
+
+
+
+ IndexedDB Test
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dom/indexedDB/test/unit/test_blob_file_backed.js b/dom/indexedDB/test/unit/test_blob_file_backed.js
new file mode 100644
index 00000000000..f3cc13cfa93
--- /dev/null
+++ b/dom/indexedDB/test/unit/test_blob_file_backed.js
@@ -0,0 +1,95 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+let testGenerator = testSteps();
+
+function createFileReader() {
+ return SpecialPowers.Cc["@mozilla.org/files/filereader;1"]
+ .createInstance(SpecialPowers.Ci.nsIDOMFileReader);
+}
+
+function testSteps()
+{
+ const fileIOFlags = 0x02 | // PR_WRONLY
+ 0x08 | // PR_CREATEFILE
+ 0x20; // PR_TRUNCATE
+ const filePerms = 0664;
+ const fileData = "abcdefghijklmnopqrstuvwxyz";
+ const fileType = "text/plain";
+
+ const databaseName =
+ ("window" in this) ? window.location.pathname : "Test";
+ const objectStoreName = "foo";
+ const objectStoreKey = "10";
+
+ info("Creating temp file");
+
+ let dirSvc =
+ SpecialPowers.Cc["@mozilla.org/file/directory_service;1"]
+ .getService(SpecialPowers.Ci.nsIProperties);
+ let testFile = dirSvc.get("ProfD", SpecialPowers.Ci.nsIFile);
+ testFile.createUnique(SpecialPowers.Ci.nsIFile.NORMAL_FILE_TYPE, filePerms);
+
+ info("Writing temp file");
+
+ let outStream =
+ SpecialPowers.Cc["@mozilla.org/network/file-output-stream;1"]
+ .createInstance(SpecialPowers.Ci.nsIFileOutputStream);
+ outStream.init(testFile, fileIOFlags, filePerms, 0);
+ outStream.write(fileData, fileData.length);
+ outStream.close();
+
+ let file = SpecialPowers.createDOMFile(testFile.path, { type: fileType });
+ ok(file instanceof File, "Got a File object");
+ is(file.size, fileData.length, "Correct size");
+ is(file.type, fileType, "Correct type");
+
+ let fileReader = createFileReader();
+ fileReader.onload = grabEventAndContinueHandler;
+ fileReader.readAsText(file);
+
+ let event = yield undefined;
+
+ is(fileReader.result, fileData, "Correct data");
+
+ let request = indexedDB.open(databaseName, 1);
+ request.onerror = errorHandler;
+ request.onupgradeneeded = grabEventAndContinueHandler;
+ request.onsuccess = grabEventAndContinueHandler;
+
+ event = yield undefined;
+
+ let db = event.target.result;
+ let objectStore = db.createObjectStore(objectStoreName);
+ objectStore.put(file, objectStoreKey);
+
+ event = yield undefined;
+
+ db = event.target.result;
+
+ file = null;
+ testFile.remove(false);
+
+ objectStore = db.transaction(objectStoreName).objectStore(objectStoreName);
+ objectStore.get(objectStoreKey).onsuccess = grabEventAndContinueHandler;
+
+ event = yield undefined;
+
+ file = event.target.result;
+
+ ok(file instanceof File, "Got a File object");
+ is(file.size, fileData.length, "Correct size");
+ is(file.type, fileType, "Correct type");
+
+ fileReader = createFileReader();
+ fileReader.onload = grabEventAndContinueHandler;
+ fileReader.readAsText(file);
+
+ event = yield undefined;
+
+ is(fileReader.result, fileData, "Correct data");
+
+ finishTest();
+ yield undefined;
+}
diff --git a/dom/indexedDB/test/unit/xpcshell-head-parent-process.js b/dom/indexedDB/test/unit/xpcshell-head-parent-process.js
index 29f0d2d5d82..c359b0a8cda 100644
--- a/dom/indexedDB/test/unit/xpcshell-head-parent-process.js
+++ b/dom/indexedDB/test/unit/xpcshell-head-parent-process.js
@@ -46,7 +46,7 @@ if (!this.runTest) {
enableExperimental();
}
- Cu.importGlobalProperties(["indexedDB"]);
+ Cu.importGlobalProperties(["indexedDB", "Blob", "File"]);
do_test_pending();
testGenerator.next();
@@ -332,5 +332,21 @@ var SpecialPowers = {
var prefService =
Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService);
return prefService.getBranch(null);
- }
+ },
+
+ get Cc() {
+ return Cc;
+ },
+
+ get Ci() {
+ return Ci;
+ },
+
+ get Cu() {
+ return Cu;
+ },
+
+ createDOMFile: function(file, options) {
+ return new File(file, options);
+ },
};
diff --git a/dom/indexedDB/test/unit/xpcshell-parent-process.ini b/dom/indexedDB/test/unit/xpcshell-parent-process.ini
index 4f076c5a703..01e21eeb9e4 100644
--- a/dom/indexedDB/test/unit/xpcshell-parent-process.ini
+++ b/dom/indexedDB/test/unit/xpcshell-parent-process.ini
@@ -18,6 +18,7 @@ support-files =
[include:xpcshell-shared.ini]
+[test_blob_file_backed.js]
[test_bug1056939.js]
[test_globalObjects_ipc.js]
[test_invalidate.js]
diff --git a/dom/ipc/Blob.cpp b/dom/ipc/Blob.cpp
index 82e8eaaf690..a7636a96fc4 100644
--- a/dom/ipc/Blob.cpp
+++ b/dom/ipc/Blob.cpp
@@ -21,6 +21,7 @@
#include "mozilla/dom/nsIContentChild.h"
#include "mozilla/dom/PBlobStreamChild.h"
#include "mozilla/dom/PBlobStreamParent.h"
+#include "mozilla/dom/indexedDB/FileSnapshot.h"
#include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
#include "mozilla/ipc/InputStreamUtils.h"
#include "mozilla/ipc/PBackgroundChild.h"
@@ -837,13 +838,13 @@ struct MOZ_STACK_CLASS CreateBlobImplMetadata MOZ_FINAL
uint64_t mLength;
uint64_t mLastModifiedDate;
bool mHasRecursed;
- bool mIsSameProcessActor;
+ const bool mIsSameProcessActor;
- CreateBlobImplMetadata()
+ CreateBlobImplMetadata(bool aIsSameProcessActor)
: mLength(0)
, mLastModifiedDate(0)
, mHasRecursed(false)
- , mIsSameProcessActor(false)
+ , mIsSameProcessActor(aIsSameProcessActor)
{
MOZ_COUNT_CTOR(CreateBlobImplMetadata);
@@ -863,10 +864,30 @@ struct MOZ_STACK_CLASS CreateBlobImplMetadata MOZ_FINAL
};
already_AddRefed
-CreateBlobImplFromParams(const StringInputStreamParams& aParams,
- const CreateBlobImplMetadata& aMetadata)
+CreateBlobImpl(const nsID& aKnownBlobIDData,
+ const CreateBlobImplMetadata& aMetadata)
{
- static_assert(sizeof(aParams.data().Length()) <= sizeof(size_t),
+ MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
+ MOZ_ASSERT(aMetadata.mHasRecursed);
+
+ nsRefPtr blobImpl = BlobParent::GetBlobImplForID(aKnownBlobIDData);
+ if (NS_WARN_IF(!blobImpl)) {
+ ASSERT_UNLESS_FUZZING();
+ return nullptr;
+ }
+
+ DebugOnly isMutable;
+ MOZ_ASSERT(NS_SUCCEEDED(blobImpl->GetMutable(&isMutable)));
+ MOZ_ASSERT(!isMutable);
+
+ return blobImpl.forget();
+}
+
+already_AddRefed
+CreateBlobImpl(const nsTArray& aMemoryData,
+ const CreateBlobImplMetadata& aMetadata)
+{
+ static_assert(sizeof(aMemoryData.Length()) <= sizeof(size_t),
"String length won't fit in size_t!");
static_assert(sizeof(size_t) <= sizeof(uint64_t),
"size_t won't fit in uint64_t!");
@@ -875,19 +896,22 @@ CreateBlobImplFromParams(const StringInputStreamParams& aParams,
nsRefPtr blobImpl;
- if (auto length = static_cast(aParams.data().Length())) {
+ if (auto length = static_cast(aMemoryData.Length())) {
+ static MOZ_CONSTEXPR_VAR size_t elementSizeMultiplier =
+ sizeof(aMemoryData[0]) / sizeof(char);
+
if (!aMetadata.mHasRecursed &&
NS_WARN_IF(aMetadata.mLength != uint64_t(length))) {
ASSERT_UNLESS_FUZZING();
return nullptr;
}
- void* buffer = moz_malloc(aParams.data().Length());
+ void* buffer = moz_malloc(length * elementSizeMultiplier);
if (NS_WARN_IF(!buffer)) {
return nullptr;
}
- memcpy(buffer, aParams.data().get(), length);
+ memcpy(buffer, aMemoryData.Elements(), length * elementSizeMultiplier);
if (!aMetadata.mHasRecursed && aMetadata.IsFile()) {
blobImpl =
@@ -915,36 +939,16 @@ CreateBlobImplFromParams(const StringInputStreamParams& aParams,
}
already_AddRefed
-CreateBlobImplFromParams(const RemoteInputStreamParams& aParams,
- const CreateBlobImplMetadata& aMetadata)
-{
- MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
- MOZ_ASSERT(aMetadata.mHasRecursed);
-
- nsRefPtr blobImpl = BlobParent::GetBlobImplForID(aParams.id());
- if (NS_WARN_IF(!blobImpl)) {
- ASSERT_UNLESS_FUZZING();
- return nullptr;
- }
-
- DebugOnly isMutable;
- MOZ_ASSERT(NS_SUCCEEDED(blobImpl->GetMutable(&isMutable)));
- MOZ_ASSERT(!isMutable);
-
- return blobImpl.forget();
-}
-
-already_AddRefed
-CreateBlobImplFromParams(const SameProcessInputStreamParams& aParams,
- const CreateBlobImplMetadata& aMetadata)
+CreateBlobImpl(intptr_t aAddRefedInputStream,
+ const CreateBlobImplMetadata& aMetadata)
{
MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
MOZ_ASSERT(aMetadata.mIsSameProcessActor);
- MOZ_ASSERT(aParams.addRefedInputStream());
+ MOZ_ASSERT(aAddRefedInputStream);
nsCOMPtr inputStream =
dont_AddRef(
- reinterpret_cast(aParams.addRefedInputStream()));
+ reinterpret_cast(aAddRefedInputStream));
nsRefPtr blobImpl;
if (!aMetadata.mHasRecursed && aMetadata.IsFile()) {
@@ -969,73 +973,35 @@ CreateBlobImplFromParams(const SameProcessInputStreamParams& aParams,
}
already_AddRefed
-CreateBlobImplFromParams(const MultiplexInputStreamParams& aParams,
- CreateBlobImplMetadata& aMetadata);
+CreateBlobImpl(const nsTArray& aBlobData,
+ CreateBlobImplMetadata& aMetadata);
already_AddRefed
-CreateBlobImplFromInputStreamParams(const InputStreamParams& aParams,
- CreateBlobImplMetadata& aMetadata)
+CreateBlobImplFromBlobData(const BlobData& aBlobData,
+ CreateBlobImplMetadata& aMetadata)
{
MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
nsRefPtr blobImpl;
- switch (aParams.type()) {
- case InputStreamParams::TStringInputStreamParams: {
- const StringInputStreamParams& params =
- aParams.get_StringInputStreamParams();
- blobImpl = CreateBlobImplFromParams(params, aMetadata);
+ switch (aBlobData.type()) {
+ case BlobData::TnsID: {
+ blobImpl = CreateBlobImpl(aBlobData.get_nsID(), aMetadata);
break;
}
- case InputStreamParams::TFileInputStreamParams: {
- ASSERT_UNLESS_FUZZING();
- return nullptr;
- }
-
- case InputStreamParams::TPartialFileInputStreamParams: {
- ASSERT_UNLESS_FUZZING();
- return nullptr;
- }
-
- case InputStreamParams::TBufferedInputStreamParams: {
- ASSERT_UNLESS_FUZZING();
- return nullptr;
- }
-
- case InputStreamParams::TMIMEInputStreamParams: {
- ASSERT_UNLESS_FUZZING();
- return nullptr;
- }
-
- case InputStreamParams::TMultiplexInputStreamParams: {
- const MultiplexInputStreamParams& params =
- aParams.get_MultiplexInputStreamParams();
- blobImpl = CreateBlobImplFromParams(params, aMetadata);
+ case BlobData::TArrayOfuint8_t: {
+ blobImpl = CreateBlobImpl(aBlobData.get_ArrayOfuint8_t(), aMetadata);
break;
}
- case InputStreamParams::TRemoteInputStreamParams: {
- if (NS_WARN_IF(!aMetadata.mHasRecursed)) {
- ASSERT_UNLESS_FUZZING();
- return nullptr;
- }
-
- const RemoteInputStreamParams& params =
- aParams.get_RemoteInputStreamParams();
- blobImpl = CreateBlobImplFromParams(params, aMetadata);
+ case BlobData::Tintptr_t: {
+ blobImpl = CreateBlobImpl(aBlobData.get_intptr_t(), aMetadata);
break;
}
- case InputStreamParams::TSameProcessInputStreamParams: {
- if (NS_WARN_IF(!aMetadata.mIsSameProcessActor)) {
- ASSERT_UNLESS_FUZZING();
- return nullptr;
- }
-
- const SameProcessInputStreamParams& params =
- aParams.get_SameProcessInputStreamParams();
- blobImpl = CreateBlobImplFromParams(params, aMetadata);
+ case BlobData::TArrayOfBlobData: {
+ blobImpl = CreateBlobImpl(aBlobData.get_ArrayOfBlobData(), aMetadata);
break;
}
@@ -1047,34 +1013,17 @@ CreateBlobImplFromInputStreamParams(const InputStreamParams& aParams,
}
already_AddRefed
-CreateBlobImplFromParams(const MultiplexInputStreamParams& aParams,
- CreateBlobImplMetadata& aMetadata)
+CreateBlobImpl(const nsTArray& aBlobDatas,
+ CreateBlobImplMetadata& aMetadata)
{
MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
- if (NS_WARN_IF(aParams.currentStream())) {
- ASSERT_UNLESS_FUZZING();
- return nullptr;
- }
-
- if (NS_WARN_IF(NS_FAILED(aParams.status()))) {
- ASSERT_UNLESS_FUZZING();
- return nullptr;
- }
-
- if (NS_WARN_IF(aParams.startedReadingCurrent())) {
- ASSERT_UNLESS_FUZZING();
- return nullptr;
- }
-
- const nsTArray& streams = aParams.streams();
-
// Special case for a multipart blob with only one part.
- if (streams.Length() == 1) {
- const InputStreamParams& params = streams[0];
+ if (aBlobDatas.Length() == 1) {
+ const BlobData& blobData = aBlobDatas[0];
nsRefPtr blobImpl =
- CreateBlobImplFromInputStreamParams(params, aMetadata);
+ CreateBlobImplFromBlobData(blobData, aMetadata);
if (NS_WARN_IF(!blobImpl)) {
return nullptr;
}
@@ -1087,7 +1036,7 @@ CreateBlobImplFromParams(const MultiplexInputStreamParams& aParams,
}
FallibleTArray> fallibleBlobImpls;
- if (NS_WARN_IF(!fallibleBlobImpls.SetLength(streams.Length()))) {
+ if (NS_WARN_IF(!fallibleBlobImpls.SetLength(aBlobDatas.Length()))) {
return nullptr;
}
@@ -1097,11 +1046,13 @@ CreateBlobImplFromParams(const MultiplexInputStreamParams& aParams,
const bool hasRecursed = aMetadata.mHasRecursed;
aMetadata.mHasRecursed = true;
- for (uint32_t count = streams.Length(), index = 0; index < count; index++) {
- const InputStreamParams& params = streams[index];
+ for (uint32_t count = aBlobDatas.Length(), index = 0;
+ index < count;
+ index++) {
+ const BlobData& blobData = aBlobDatas[index];
nsRefPtr& blobImpl = blobImpls[index];
- blobImpl = CreateBlobImplFromParams(params, aMetadata);
+ blobImpl = CreateBlobImplFromBlobData(blobData, aMetadata);
if (NS_WARN_IF(!blobImpl)) {
return nullptr;
}
@@ -1126,18 +1077,17 @@ CreateBlobImplFromParams(const MultiplexInputStreamParams& aParams,
}
already_AddRefed
-CreateBlobImplFromParams(const ParentBlobConstructorParams& aParams,
- bool aIsSameProcessActor)
+CreateBlobImpl(const ParentBlobConstructorParams& aParams,
+ const BlobData& aBlobData,
+ bool aIsSameProcessActor)
{
MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
MOZ_ASSERT(aParams.blobParams().type() ==
AnyBlobConstructorParams::TNormalBlobConstructorParams ||
aParams.blobParams().type() ==
AnyBlobConstructorParams::TFileBlobConstructorParams);
- MOZ_ASSERT(aParams.optionalInputStreamParams().type() ==
- OptionalInputStreamParams::TInputStreamParams);
- CreateBlobImplMetadata metadata;
+ CreateBlobImplMetadata metadata(aIsSameProcessActor);
if (aParams.blobParams().type() ==
AnyBlobConstructorParams::TNormalBlobConstructorParams) {
@@ -1171,16 +1121,71 @@ CreateBlobImplFromParams(const ParentBlobConstructorParams& aParams,
metadata.mLastModifiedDate = params.modDate();
}
- metadata.mIsSameProcessActor = aIsSameProcessActor;
-
- const InputStreamParams& inputStreamParams =
- aParams.optionalInputStreamParams().get_InputStreamParams();
-
nsRefPtr blobImpl =
- CreateBlobImplFromInputStreamParams(inputStreamParams, metadata);
+ CreateBlobImplFromBlobData(aBlobData, metadata);
return blobImpl.forget();
}
+void
+BlobDataFromBlobImpl(FileImpl* aBlobImpl, BlobData& aBlobData)
+{
+ MOZ_ASSERT(gProcessType != GeckoProcessType_Default);
+ MOZ_ASSERT(aBlobImpl);
+
+ const nsTArray>* subBlobs = aBlobImpl->GetSubBlobImpls();
+
+ if (subBlobs) {
+ aBlobData = nsTArray();
+
+ nsTArray& subBlobDatas = aBlobData.get_ArrayOfBlobData();
+ subBlobDatas.SetLength(subBlobs->Length());
+
+ for (uint32_t count = subBlobs->Length(), index = 0;
+ index < count;
+ index++) {
+ BlobDataFromBlobImpl(subBlobs->ElementAt(index), subBlobDatas[index]);
+ }
+
+ return;
+ }
+
+ nsCOMPtr remoteBlob = do_QueryInterface(aBlobImpl);
+ if (remoteBlob) {
+ BlobChild* actor = remoteBlob->GetBlobChild();
+ MOZ_ASSERT(actor);
+
+ aBlobData = actor->ParentID();
+ return;
+ }
+
+ MOZ_ASSERT(aBlobImpl->IsMemoryFile());
+
+ nsCOMPtr inputStream;
+ MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
+ aBlobImpl->GetInternalStream(getter_AddRefs(inputStream))));
+
+ DebugOnly isNonBlocking;
+ MOZ_ASSERT(NS_SUCCEEDED(inputStream->IsNonBlocking(&isNonBlocking)));
+ MOZ_ASSERT(isNonBlocking);
+
+ uint64_t available;
+ MOZ_ALWAYS_TRUE(NS_SUCCEEDED(inputStream->Available(&available)));
+
+ MOZ_ASSERT(available <= uint64_t(UINT32_MAX));
+
+ aBlobData = nsTArray();
+
+ nsTArray& blobData = aBlobData.get_ArrayOfuint8_t();
+
+ blobData.SetLength(size_t(available));
+
+ uint32_t readCount;
+ MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
+ inputStream->Read(reinterpret_cast(blobData.Elements()),
+ uint32_t(available),
+ &readCount)));
+}
+
} // anonymous namespace
StaticAutoPtr BlobParent::sIDTable;
@@ -1548,6 +1553,9 @@ protected:
BlobChild* mActor;
nsCOMPtr mActorTarget;
+
+ nsRefPtr mSameProcessFileImpl;
+
const bool mIsSlice;
public:
@@ -1563,6 +1571,20 @@ public:
const nsAString& aContentType,
uint64_t aLength);
+ // For same-process blobs.
+ RemoteBlobImpl(BlobChild* aActor,
+ FileImpl* aSameProcessBlobImpl,
+ const nsAString& aName,
+ const nsAString& aContentType,
+ uint64_t aLength,
+ uint64_t aModDate);
+
+ // For same-process blobs.
+ RemoteBlobImpl(BlobChild* aActor,
+ FileImpl* aSameProcessBlobImpl,
+ const nsAString& aContentType,
+ uint64_t aLength);
+
// For mystery blobs.
explicit
RemoteBlobImpl(BlobChild* aActor);
@@ -1853,6 +1875,38 @@ RemoteBlobImpl::RemoteBlobImpl(BlobChild* aActor,
CommonInit(aActor);
}
+BlobChild::
+RemoteBlobImpl::RemoteBlobImpl(BlobChild* aActor,
+ FileImpl* aSameProcessBlobImpl,
+ const nsAString& aName,
+ const nsAString& aContentType,
+ uint64_t aLength,
+ uint64_t aModDate)
+ : FileImplBase(aName, aContentType, aLength, aModDate)
+ , mSameProcessFileImpl(aSameProcessBlobImpl)
+ , mIsSlice(false)
+{
+ MOZ_ASSERT(aSameProcessBlobImpl);
+ MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
+
+ CommonInit(aActor);
+}
+
+BlobChild::
+RemoteBlobImpl::RemoteBlobImpl(BlobChild* aActor,
+ FileImpl* aSameProcessBlobImpl,
+ const nsAString& aContentType,
+ uint64_t aLength)
+ : FileImplBase(aContentType, aLength)
+ , mSameProcessFileImpl(aSameProcessBlobImpl)
+ , mIsSlice(false)
+{
+ MOZ_ASSERT(aSameProcessBlobImpl);
+ MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
+
+ CommonInit(aActor);
+}
+
BlobChild::
RemoteBlobImpl::RemoteBlobImpl(BlobChild* aActor)
: FileImplBase(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX)
@@ -1954,6 +2008,13 @@ RemoteBlobImpl::GetMozFullPathInternal(nsAString& aFilePath,
MOZ_CRASH("Not implemented!");
}
+ if (mSameProcessFileImpl) {
+ MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
+
+ mSameProcessFileImpl->GetMozFullPathInternal(aFilePath, aRv);
+ return;
+ }
+
if (!mActor) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return;
@@ -1976,9 +2037,18 @@ RemoteBlobImpl::CreateSlice(uint64_t aStart,
ErrorResult& aRv)
{
// May be called on any thread.
- nsRefPtr slice =
- new RemoteBlobSliceImpl(this, aStart, aLength, aContentType);
- return slice.forget();
+ if (mSameProcessFileImpl) {
+ MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
+
+ return mSameProcessFileImpl->CreateSlice(aStart,
+ aLength,
+ aContentType,
+ aRv);
+ }
+
+ nsRefPtr slice =
+ new RemoteBlobSliceImpl(this, aStart, aLength, aContentType);
+ return slice.forget();
}
nsresult
@@ -1986,6 +2056,22 @@ BlobChild::
RemoteBlobImpl::GetInternalStream(nsIInputStream** aStream)
{
// May be called on any thread.
+ if (mSameProcessFileImpl) {
+ MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
+
+ nsCOMPtr realStream;
+ nsresult rv =
+ mSameProcessFileImpl->GetInternalStream(getter_AddRefs(realStream));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ nsRefPtr tether =
+ new BlobInputStreamTether(realStream, mSameProcessFileImpl);
+ tether.forget(aStream);
+ return NS_OK;
+ }
+
nsRefPtr helper = new CreateStreamHelper(this);
return helper->GetStream(aStream);
}
@@ -1998,6 +2084,12 @@ RemoteBlobImpl::GetFileId()
MOZ_CRASH("Not implemented!");
}
+ if (mSameProcessFileImpl) {
+ MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
+
+ return mSameProcessFileImpl->GetFileId();
+ }
+
int64_t fileId;
if (mActor && mActor->SendGetFileId(&fileId)) {
return fileId;
@@ -2209,8 +2301,7 @@ RemoteBlobSliceImpl::GetBlobChild()
id /* id */,
mStart /* begin */,
mStart + mLength /* end */,
- mContentType /* contentType */),
- void_t() /* optionalInputStream */);
+ mContentType /* contentType */));
if (nsIContentChild* contentManager = baseActor->GetContentManager()) {
mActor = SendSliceConstructor(contentManager, this, params);
@@ -2648,6 +2739,8 @@ BlobChild::CommonInit(const ChildBlobConstructorParams& aParams)
AnyBlobConstructorParams::Type paramsType = blobParams.type();
MOZ_ASSERT(paramsType != AnyBlobConstructorParams::T__None &&
+ paramsType !=
+ AnyBlobConstructorParams::TSlicedBlobConstructorParams &&
paramsType !=
AnyBlobConstructorParams::TKnownBlobConstructorParams);
@@ -2673,6 +2766,44 @@ BlobChild::CommonInit(const ChildBlobConstructorParams& aParams)
break;
}
+ case AnyBlobConstructorParams::TSameProcessBlobConstructorParams: {
+ MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
+
+ const SameProcessBlobConstructorParams& params =
+ blobParams.get_SameProcessBlobConstructorParams();
+ MOZ_ASSERT(params.addRefedFileImpl());
+
+ nsRefPtr blobImpl =
+ dont_AddRef(reinterpret_cast(params.addRefedFileImpl()));
+
+ ErrorResult rv;
+ uint64_t size = blobImpl->GetSize(rv);
+ MOZ_ASSERT(!rv.Failed());
+
+ nsString contentType;
+ blobImpl->GetType(contentType);
+
+ if (blobImpl->IsFile()) {
+ nsString name;
+ blobImpl->GetName(name);
+
+ uint64_t lastModifiedDate = blobImpl->GetLastModified(rv);
+ MOZ_ASSERT(!rv.Failed());
+
+ remoteBlob =
+ new RemoteBlobImpl(this,
+ blobImpl,
+ name,
+ contentType,
+ size,
+ lastModifiedDate);
+ } else {
+ remoteBlob = new RemoteBlobImpl(this, blobImpl, contentType, size);
+ }
+
+ break;
+ }
+
case AnyBlobConstructorParams::TMysteryBlobConstructorParams: {
remoteBlob = new RemoteBlobImpl(this);
break;
@@ -2798,7 +2929,7 @@ BlobChild::GetOrCreateFromImpl(ChildManagerType* aManager,
}
}
- // All blobs shared between processes must be immutable.
+ // All blobs shared between threads or processes must be immutable.
if (NS_WARN_IF(NS_FAILED(aBlobImpl->SetMutable(false)))) {
return nullptr;
}
@@ -2808,40 +2939,55 @@ BlobChild::GetOrCreateFromImpl(ChildManagerType* aManager,
AnyBlobConstructorParams blobParams;
- nsString contentType;
- aBlobImpl->GetType(contentType);
+ nsCOMPtr snapshotInputStream;
- ErrorResult rv;
- uint64_t length = aBlobImpl->GetSize(rv);
- MOZ_ASSERT(!rv.Failed());
-
- nsCOMPtr stream;
- MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
- aBlobImpl->GetInternalStream(getter_AddRefs(stream))));
-
- if (aBlobImpl->IsFile()) {
- nsString name;
- aBlobImpl->GetName(name);
-
- uint64_t modDate = aBlobImpl->GetLastModified(rv);
- MOZ_ASSERT(!rv.Failed());
-
- blobParams = FileBlobConstructorParams(name, contentType, length, modDate);
- } else {
- blobParams = NormalBlobConstructorParams(contentType, length);
+ if (gProcessType == GeckoProcessType_Default) {
+ nsCOMPtr snapshot = do_QueryInterface(aBlobImpl);
+ if (snapshot) {
+ MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
+ aBlobImpl->GetInternalStream(getter_AddRefs(snapshotInputStream))));
+ }
}
- InputStreamParams inputStreamParams;
+ if (gProcessType == GeckoProcessType_Default && !snapshotInputStream) {
+ nsRefPtr sameProcessImpl = aBlobImpl;
+ auto addRefedFileImpl =
+ reinterpret_cast(sameProcessImpl.forget().take());
- nsTArray fds;
- SerializeInputStream(stream, inputStreamParams, fds);
+ blobParams = SameProcessBlobConstructorParams(addRefedFileImpl);
+ } else {
+ BlobData blobData;
+ if (snapshotInputStream) {
+ blobData =
+ reinterpret_cast(snapshotInputStream.forget().take());
+ } else {
+ BlobDataFromBlobImpl(aBlobImpl, blobData);
+ }
- MOZ_ASSERT(inputStreamParams.type() != InputStreamParams::T__None);
- MOZ_ASSERT(fds.IsEmpty());
+ nsString contentType;
+ aBlobImpl->GetType(contentType);
+
+ ErrorResult rv;
+ uint64_t length = aBlobImpl->GetSize(rv);
+ MOZ_ASSERT(!rv.Failed());
+
+ if (aBlobImpl->IsFile()) {
+ nsString name;
+ aBlobImpl->GetName(name);
+
+ uint64_t modDate = aBlobImpl->GetLastModified(rv);
+ MOZ_ASSERT(!rv.Failed());
+
+ blobParams =
+ FileBlobConstructorParams(name, contentType, length, modDate, blobData);
+ } else {
+ blobParams = NormalBlobConstructorParams(contentType, length, blobData);
+ }
+ }
BlobChild* actor = new BlobChild(aManager, aBlobImpl);
- ParentBlobConstructorParams params(blobParams, inputStreamParams);
+ ParentBlobConstructorParams params(blobParams);
if (NS_WARN_IF(!aManager->SendPBlobConstructor(actor, params))) {
BlobChild::Destroy(actor);
@@ -2865,6 +3011,7 @@ BlobChild::CreateFromParams(ChildManagerType* aManager,
switch (blobParams.type()) {
case AnyBlobConstructorParams::TNormalBlobConstructorParams:
case AnyBlobConstructorParams::TFileBlobConstructorParams:
+ case AnyBlobConstructorParams::TSameProcessBlobConstructorParams:
case AnyBlobConstructorParams::TMysteryBlobConstructorParams: {
return new BlobChild(aManager, aParams);
}
@@ -2896,8 +3043,6 @@ BlobChild::SendSliceConstructor(ChildManagerType* aManager,
MOZ_ASSERT(aRemoteBlobSliceImpl);
MOZ_ASSERT(aParams.blobParams().type() ==
AnyBlobConstructorParams::TSlicedBlobConstructorParams);
- MOZ_ASSERT(aParams.optionalInputStreamParams().type() ==
- OptionalInputStreamParams::Tvoid_t);
const nsID& id = aParams.blobParams().get_SlicedBlobConstructorParams().id();
@@ -2933,8 +3078,7 @@ BlobChild::MaybeGetActorFromRemoteBlob(nsIRemoteBlob* aRemoteBlob,
actor = new BlobChild(aManager, actor);
ParentBlobConstructorParams params(
- KnownBlobConstructorParams(actor->ParentID()) /* blobParams */,
- void_t() /* optionalInputStream */);
+ KnownBlobConstructorParams(actor->ParentID()));
aManager->SendPBlobConstructor(actor, params);
@@ -2963,8 +3107,7 @@ BlobChild::MaybeGetActorFromRemoteBlob(nsIRemoteBlob* aRemoteBlob,
actor = new BlobChild(aManager, actor);
ParentBlobConstructorParams params(
- KnownBlobConstructorParams(actor->ParentID()) /* blobParams */,
- void_t() /* optionalInputStream */);
+ KnownBlobConstructorParams(actor->ParentID()));
aManager->SendPBlobConstructor(actor, params);
@@ -3019,8 +3162,11 @@ BlobChild::SetMysteryBlobInfo(const nsString& aName,
mBlobImpl->SetLazyData(aName, aContentType, aLength, aLastModifiedDate);
- FileBlobConstructorParams params(aName, aContentType, aLength,
- aLastModifiedDate);
+ FileBlobConstructorParams params(aName,
+ aContentType,
+ aLength,
+ aLastModifiedDate,
+ void_t() /* optionalBlobData */);
return SendResolveMystery(params);
}
@@ -3036,7 +3182,9 @@ BlobChild::SetMysteryBlobInfo(const nsString& aContentType, uint64_t aLength)
mBlobImpl->SetLazyData(voidString, aContentType, aLength, UINT64_MAX);
- NormalBlobConstructorParams params(aContentType, aLength);
+ NormalBlobConstructorParams params(aContentType,
+ aLength,
+ void_t() /* optionalBlobData */);
return SendResolveMystery(params);
}
@@ -3326,37 +3474,56 @@ BlobParent::GetOrCreateFromImpl(ParentManagerType* aManager,
}
}
- // All blobs shared between processes must be immutable.
+ // All blobs shared between threads or processes must be immutable.
if (NS_WARN_IF(NS_FAILED(aBlobImpl->SetMutable(false)))) {
return nullptr;
}
+ const bool isSameProcessActor = ActorManagerIsSameProcess(aManager);
+
AnyBlobConstructorParams blobParams;
- if (aBlobImpl->IsSizeUnknown() || aBlobImpl->IsDateUnknown()) {
- // We don't want to call GetSize or GetLastModifiedDate yet since that may
- // stat a file on the this thread. Instead we'll learn the size lazily from
- // the other side.
- blobParams = MysteryBlobConstructorParams();
+ bool isSnapshot;
+
+ if (isSameProcessActor) {
+ nsCOMPtr snapshot = do_QueryInterface(aBlobImpl);
+ isSnapshot = !!snapshot;
} else {
- nsString contentType;
- aBlobImpl->GetType(contentType);
+ isSnapshot = false;
+ }
- ErrorResult rv;
- uint64_t length = aBlobImpl->GetSize(rv);
- MOZ_ASSERT(!rv.Failed());
+ if (isSameProcessActor && !isSnapshot) {
+ nsRefPtr sameProcessImpl = aBlobImpl;
+ auto addRefedFileImpl =
+ reinterpret_cast(sameProcessImpl.forget().take());
- if (aBlobImpl->IsFile()) {
- nsString name;
- aBlobImpl->GetName(name);
+ blobParams = SameProcessBlobConstructorParams(addRefedFileImpl);
+ } else {
+ if (aBlobImpl->IsSizeUnknown() || aBlobImpl->IsDateUnknown()) {
+ // We don't want to call GetSize or GetLastModifiedDate yet since that may
+ // stat a file on the this thread. Instead we'll learn the size lazily
+ // from the other side.
+ blobParams = MysteryBlobConstructorParams();
+ } else {
+ nsString contentType;
+ aBlobImpl->GetType(contentType);
- uint64_t modDate = aBlobImpl->GetLastModified(rv);
+ ErrorResult rv;
+ uint64_t length = aBlobImpl->GetSize(rv);
MOZ_ASSERT(!rv.Failed());
- blobParams =
- FileBlobConstructorParams(name, contentType, length, modDate);
- } else {
- blobParams = NormalBlobConstructorParams(contentType, length);
+ if (aBlobImpl->IsFile()) {
+ nsString name;
+ aBlobImpl->GetName(name);
+
+ uint64_t modDate = aBlobImpl->GetLastModified(rv);
+ MOZ_ASSERT(!rv.Failed());
+
+ blobParams =
+ FileBlobConstructorParams(name, contentType, length, modDate, void_t());
+ } else {
+ blobParams = NormalBlobConstructorParams(contentType, length, void_t());
+ }
}
}
@@ -3397,14 +3564,21 @@ BlobParent::CreateFromParams(ParentManagerType* aManager,
case AnyBlobConstructorParams::TNormalBlobConstructorParams:
case AnyBlobConstructorParams::TFileBlobConstructorParams: {
- if (aParams.optionalInputStreamParams().type() !=
- OptionalInputStreamParams::TInputStreamParams) {
+ const OptionalBlobData& optionalBlobData =
+ blobParams.type() ==
+ AnyBlobConstructorParams::TNormalBlobConstructorParams ?
+ blobParams.get_NormalBlobConstructorParams().optionalBlobData() :
+ blobParams.get_FileBlobConstructorParams().optionalBlobData();
+
+ if (NS_WARN_IF(optionalBlobData.type() != OptionalBlobData::TBlobData)) {
ASSERT_UNLESS_FUZZING();
return nullptr;
}
nsRefPtr blobImpl =
- CreateBlobImplFromParams(aParams, ActorManagerIsSameProcess(aManager));
+ CreateBlobImpl(aParams,
+ optionalBlobData.get_BlobData(),
+ ActorManagerIsSameProcess(aManager));
if (NS_WARN_IF(!blobImpl)) {
ASSERT_UNLESS_FUZZING();
return nullptr;
@@ -3424,12 +3598,6 @@ BlobParent::CreateFromParams(ParentManagerType* aManager,
}
case AnyBlobConstructorParams::TSlicedBlobConstructorParams: {
- if (aParams.optionalInputStreamParams().type() !=
- OptionalInputStreamParams::Tvoid_t) {
- ASSERT_UNLESS_FUZZING();
- return nullptr;
- }
-
const SlicedBlobConstructorParams& params =
blobParams.get_SlicedBlobConstructorParams();
@@ -3472,12 +3640,6 @@ BlobParent::CreateFromParams(ParentManagerType* aManager,
}
case AnyBlobConstructorParams::TKnownBlobConstructorParams: {
- if (aParams.optionalInputStreamParams().type() !=
- OptionalInputStreamParams::Tvoid_t) {
- ASSERT_UNLESS_FUZZING();
- return nullptr;
- }
-
const KnownBlobConstructorParams& params =
blobParams.get_KnownBlobConstructorParams();
@@ -3494,6 +3656,29 @@ BlobParent::CreateFromParams(ParentManagerType* aManager,
return new BlobParent(aManager, blobImpl, idTableEntry);
}
+ case AnyBlobConstructorParams::TSameProcessBlobConstructorParams: {
+ if (NS_WARN_IF(!ActorManagerIsSameProcess(aManager))) {
+ ASSERT_UNLESS_FUZZING();
+ return nullptr;
+ }
+
+ const SameProcessBlobConstructorParams& params =
+ blobParams.get_SameProcessBlobConstructorParams();
+
+ nsRefPtr blobImpl =
+ dont_AddRef(reinterpret_cast(params.addRefedFileImpl()));
+ MOZ_ASSERT(blobImpl);
+
+ nsID id;
+ MOZ_ALWAYS_TRUE(NS_SUCCEEDED(gUUIDGenerator->GenerateUUIDInPlace(&id)));
+
+ nsRefPtr idTableEntry =
+ IDTableEntry::Create(id, ActorManagerProcessID(aManager), blobImpl);
+ MOZ_ASSERT(idTableEntry);
+
+ return new BlobParent(aManager, blobImpl, idTableEntry);
+ }
+
default:
MOZ_CRASH("Unknown params!");
}
diff --git a/dom/ipc/DOMTypes.ipdlh b/dom/ipc/DOMTypes.ipdlh
index 0dc59456238..d1a2c73c323 100644
--- a/dom/ipc/DOMTypes.ipdlh
+++ b/dom/ipc/DOMTypes.ipdlh
@@ -5,7 +5,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
include protocol PBlob;
-include InputStreamParams;
using struct mozilla::void_t
from "ipc/IPCMessageUtils.h";
@@ -13,6 +12,9 @@ using struct mozilla::void_t
using struct mozilla::SerializedStructuredCloneBuffer
from "ipc/IPCMessageUtils.h";
+using struct nsID
+ from "nsID.h";
+
namespace mozilla {
namespace dom {
@@ -28,10 +30,35 @@ struct ClonedMessageData
PBlob[] blobs;
};
+union BlobData
+{
+ // For remote blobs.
+ nsID;
+
+ // For memory-backed blobs.
+ uint8_t[];
+
+ // For file snapshots, this is an nsIInputStream.
+ intptr_t;
+
+ // For multiplex blobs.
+ BlobData[];
+};
+
+union OptionalBlobData
+{
+ BlobData;
+ void_t;
+};
+
struct NormalBlobConstructorParams
{
nsString contentType;
uint64_t length;
+
+ // This must be of type BlobData in a child->parent message, and will always
+ // be of type void_t in a parent->child message.
+ OptionalBlobData optionalBlobData;
};
struct FileBlobConstructorParams
@@ -40,6 +67,10 @@ struct FileBlobConstructorParams
nsString contentType;
uint64_t length;
uint64_t modDate;
+
+ // This must be of type BlobData in a child->parent message, and will always
+ // be of type void_t in a parent->child message.
+ OptionalBlobData optionalBlobData;
};
struct SlicedBlobConstructorParams
@@ -61,11 +92,20 @@ struct KnownBlobConstructorParams
nsID id;
};
+// This may only be used for same-process inter-thread communication!
+struct SameProcessBlobConstructorParams
+{
+ // This member should be reinterpret_cast'd to mozilla::dom::FileImpl. It
+ // carries a reference.
+ intptr_t addRefedFileImpl;
+};
+
union AnyBlobConstructorParams
{
// These types may be sent to/from parent and child.
NormalBlobConstructorParams;
FileBlobConstructorParams;
+ SameProcessBlobConstructorParams;
// This type may only be sent from parent to child.
MysteryBlobConstructorParams;
@@ -87,14 +127,6 @@ struct ParentBlobConstructorParams
{
// May not be MysteryBlobConstructorParams.
AnyBlobConstructorParams blobParams;
-
- // This must be of type void_t for:
- // - SlicedBlobConstructorParams
- // - KnownBlobConstructorParams
- // This must be of type InputStreamParams for:
- // - NormalBlobConstructorParams
- // - FileBlobConstructorParams
- OptionalInputStreamParams optionalInputStreamParams;
};
union BlobConstructorParams
diff --git a/ipc/glue/InputStreamParams.ipdlh b/ipc/glue/InputStreamParams.ipdlh
index 936d0228bcd..752960d4b8a 100644
--- a/ipc/glue/InputStreamParams.ipdlh
+++ b/ipc/glue/InputStreamParams.ipdlh
@@ -2,13 +2,13 @@
* 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/. */
-
-using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
include protocol PBlob;
include protocol PFileDescriptorSet;
-using struct nsID
- from "nsID.h";
+include DOMTypes;
+
+using struct mozilla::void_t
+ from "ipc/IPCMessageUtils.h";
namespace mozilla {
namespace ipc {
diff --git a/testing/specialpowers/content/specialpowersAPI.js b/testing/specialpowers/content/specialpowersAPI.js
index 133a1786a73..4e34fe2bd8a 100644
--- a/testing/specialpowers/content/specialpowersAPI.js
+++ b/testing/specialpowers/content/specialpowersAPI.js
@@ -18,6 +18,8 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.importGlobalProperties(["File"]);
+
// Allow stuff from this scope to be accessed from non-privileged scopes. This
// would crash if used outside of automation.
Cu.forcePermissiveCOWs();
@@ -1877,6 +1879,10 @@ SpecialPowersAPI.prototype = {
let msg = { op: op, uri: uri, appId: appId, inBrowser: inBrowser, id: id };
this._sendAsyncMessage(messageTopic, msg);
},
+
+ createDOMFile: function(path, options) {
+ return new File(path, options);
+ },
};
this.SpecialPowersAPI = SpecialPowersAPI;