Bug 1076975 - Avoid serializing blobs when passed between threads in the same process, r=khuey.

This commit is contained in:
Ben Turner 2014-10-20 17:49:00 -07:00
parent 3fd962194d
commit e24fd2b2d7
11 changed files with 582 additions and 212 deletions

View File

@ -86,7 +86,7 @@ FileImplSnapshot::AssertSanity()
#endif // DEBUG #endif // DEBUG
NS_IMPL_ISUPPORTS_INHERITED0(FileImplSnapshot, FileImpl) NS_IMPL_ISUPPORTS_INHERITED(FileImplSnapshot, FileImpl, PIFileImplSnapshot)
void void
FileImplSnapshot::Unlink() FileImplSnapshot::Unlink()

View File

@ -11,6 +11,18 @@
#include "mozilla/dom/File.h" #include "mozilla/dom/File.h"
#include "nsAutoPtr.h" #include "nsAutoPtr.h"
#include "nsCOMPtr.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 mozilla {
namespace dom { namespace dom {
@ -23,6 +35,7 @@ class IDBFileHandle;
class FileImplSnapshot MOZ_FINAL class FileImplSnapshot MOZ_FINAL
: public FileImplBase : public FileImplBase
, public PIFileImplSnapshot
{ {
typedef mozilla::dom::MetadataParameters MetadataParameters; typedef mozilla::dom::MetadataParameters MetadataParameters;

View File

@ -19,6 +19,7 @@ support-files =
unit/test_advance.js unit/test_advance.js
unit/test_autoIncrement.js unit/test_autoIncrement.js
unit/test_autoIncrement_indexes.js unit/test_autoIncrement_indexes.js
unit/test_blob_file_backed.js
unit/test_blocked_order.js unit/test_blocked_order.js
unit/test_clear.js unit/test_clear.js
unit/test_complex_keyPaths.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 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_blob_archive.html] [test_blob_archive.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116 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] [test_blob_simple.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_blob_worker_crash.html] [test_blob_worker_crash.html]

View File

@ -0,0 +1,18 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>IndexedDB 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" src="unit/test_blob_file_backed.js"></script>
<script type="text/javascript;version=1.7" src="helpers.js"></script>
</head>
<body onload="runTest();"></body>
</html>

View File

@ -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;
}

View File

@ -46,7 +46,7 @@ if (!this.runTest) {
enableExperimental(); enableExperimental();
} }
Cu.importGlobalProperties(["indexedDB"]); Cu.importGlobalProperties(["indexedDB", "Blob", "File"]);
do_test_pending(); do_test_pending();
testGenerator.next(); testGenerator.next();
@ -332,5 +332,21 @@ var SpecialPowers = {
var prefService = var prefService =
Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService); Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService);
return prefService.getBranch(null); 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);
},
}; };

View File

@ -18,6 +18,7 @@ support-files =
[include:xpcshell-shared.ini] [include:xpcshell-shared.ini]
[test_blob_file_backed.js]
[test_bug1056939.js] [test_bug1056939.js]
[test_globalObjects_ipc.js] [test_globalObjects_ipc.js]
[test_invalidate.js] [test_invalidate.js]

View File

@ -21,6 +21,7 @@
#include "mozilla/dom/nsIContentChild.h" #include "mozilla/dom/nsIContentChild.h"
#include "mozilla/dom/PBlobStreamChild.h" #include "mozilla/dom/PBlobStreamChild.h"
#include "mozilla/dom/PBlobStreamParent.h" #include "mozilla/dom/PBlobStreamParent.h"
#include "mozilla/dom/indexedDB/FileSnapshot.h"
#include "mozilla/dom/indexedDB/IndexedDatabaseManager.h" #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
#include "mozilla/ipc/InputStreamUtils.h" #include "mozilla/ipc/InputStreamUtils.h"
#include "mozilla/ipc/PBackgroundChild.h" #include "mozilla/ipc/PBackgroundChild.h"
@ -837,13 +838,13 @@ struct MOZ_STACK_CLASS CreateBlobImplMetadata MOZ_FINAL
uint64_t mLength; uint64_t mLength;
uint64_t mLastModifiedDate; uint64_t mLastModifiedDate;
bool mHasRecursed; bool mHasRecursed;
bool mIsSameProcessActor; const bool mIsSameProcessActor;
CreateBlobImplMetadata() CreateBlobImplMetadata(bool aIsSameProcessActor)
: mLength(0) : mLength(0)
, mLastModifiedDate(0) , mLastModifiedDate(0)
, mHasRecursed(false) , mHasRecursed(false)
, mIsSameProcessActor(false) , mIsSameProcessActor(aIsSameProcessActor)
{ {
MOZ_COUNT_CTOR(CreateBlobImplMetadata); MOZ_COUNT_CTOR(CreateBlobImplMetadata);
@ -863,10 +864,30 @@ struct MOZ_STACK_CLASS CreateBlobImplMetadata MOZ_FINAL
}; };
already_AddRefed<FileImpl> already_AddRefed<FileImpl>
CreateBlobImplFromParams(const StringInputStreamParams& aParams, CreateBlobImpl(const nsID& aKnownBlobIDData,
const CreateBlobImplMetadata& aMetadata) const CreateBlobImplMetadata& aMetadata)
{ {
static_assert(sizeof(aParams.data().Length()) <= sizeof(size_t), MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
MOZ_ASSERT(aMetadata.mHasRecursed);
nsRefPtr<FileImpl> blobImpl = BlobParent::GetBlobImplForID(aKnownBlobIDData);
if (NS_WARN_IF(!blobImpl)) {
ASSERT_UNLESS_FUZZING();
return nullptr;
}
DebugOnly<bool> isMutable;
MOZ_ASSERT(NS_SUCCEEDED(blobImpl->GetMutable(&isMutable)));
MOZ_ASSERT(!isMutable);
return blobImpl.forget();
}
already_AddRefed<FileImpl>
CreateBlobImpl(const nsTArray<uint8_t>& aMemoryData,
const CreateBlobImplMetadata& aMetadata)
{
static_assert(sizeof(aMemoryData.Length()) <= sizeof(size_t),
"String length won't fit in size_t!"); "String length won't fit in size_t!");
static_assert(sizeof(size_t) <= sizeof(uint64_t), static_assert(sizeof(size_t) <= sizeof(uint64_t),
"size_t won't fit in uint64_t!"); "size_t won't fit in uint64_t!");
@ -875,19 +896,22 @@ CreateBlobImplFromParams(const StringInputStreamParams& aParams,
nsRefPtr<FileImpl> blobImpl; nsRefPtr<FileImpl> blobImpl;
if (auto length = static_cast<size_t>(aParams.data().Length())) { if (auto length = static_cast<size_t>(aMemoryData.Length())) {
static MOZ_CONSTEXPR_VAR size_t elementSizeMultiplier =
sizeof(aMemoryData[0]) / sizeof(char);
if (!aMetadata.mHasRecursed && if (!aMetadata.mHasRecursed &&
NS_WARN_IF(aMetadata.mLength != uint64_t(length))) { NS_WARN_IF(aMetadata.mLength != uint64_t(length))) {
ASSERT_UNLESS_FUZZING(); ASSERT_UNLESS_FUZZING();
return nullptr; return nullptr;
} }
void* buffer = moz_malloc(aParams.data().Length()); void* buffer = moz_malloc(length * elementSizeMultiplier);
if (NS_WARN_IF(!buffer)) { if (NS_WARN_IF(!buffer)) {
return nullptr; return nullptr;
} }
memcpy(buffer, aParams.data().get(), length); memcpy(buffer, aMemoryData.Elements(), length * elementSizeMultiplier);
if (!aMetadata.mHasRecursed && aMetadata.IsFile()) { if (!aMetadata.mHasRecursed && aMetadata.IsFile()) {
blobImpl = blobImpl =
@ -915,36 +939,16 @@ CreateBlobImplFromParams(const StringInputStreamParams& aParams,
} }
already_AddRefed<FileImpl> already_AddRefed<FileImpl>
CreateBlobImplFromParams(const RemoteInputStreamParams& aParams, CreateBlobImpl(intptr_t aAddRefedInputStream,
const CreateBlobImplMetadata& aMetadata) const CreateBlobImplMetadata& aMetadata)
{
MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
MOZ_ASSERT(aMetadata.mHasRecursed);
nsRefPtr<FileImpl> blobImpl = BlobParent::GetBlobImplForID(aParams.id());
if (NS_WARN_IF(!blobImpl)) {
ASSERT_UNLESS_FUZZING();
return nullptr;
}
DebugOnly<bool> isMutable;
MOZ_ASSERT(NS_SUCCEEDED(blobImpl->GetMutable(&isMutable)));
MOZ_ASSERT(!isMutable);
return blobImpl.forget();
}
already_AddRefed<FileImpl>
CreateBlobImplFromParams(const SameProcessInputStreamParams& aParams,
const CreateBlobImplMetadata& aMetadata)
{ {
MOZ_ASSERT(gProcessType == GeckoProcessType_Default); MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
MOZ_ASSERT(aMetadata.mIsSameProcessActor); MOZ_ASSERT(aMetadata.mIsSameProcessActor);
MOZ_ASSERT(aParams.addRefedInputStream()); MOZ_ASSERT(aAddRefedInputStream);
nsCOMPtr<nsIInputStream> inputStream = nsCOMPtr<nsIInputStream> inputStream =
dont_AddRef( dont_AddRef(
reinterpret_cast<nsIInputStream*>(aParams.addRefedInputStream())); reinterpret_cast<nsIInputStream*>(aAddRefedInputStream));
nsRefPtr<FileImpl> blobImpl; nsRefPtr<FileImpl> blobImpl;
if (!aMetadata.mHasRecursed && aMetadata.IsFile()) { if (!aMetadata.mHasRecursed && aMetadata.IsFile()) {
@ -969,73 +973,35 @@ CreateBlobImplFromParams(const SameProcessInputStreamParams& aParams,
} }
already_AddRefed<FileImpl> already_AddRefed<FileImpl>
CreateBlobImplFromParams(const MultiplexInputStreamParams& aParams, CreateBlobImpl(const nsTArray<BlobData>& aBlobData,
CreateBlobImplMetadata& aMetadata); CreateBlobImplMetadata& aMetadata);
already_AddRefed<FileImpl> already_AddRefed<FileImpl>
CreateBlobImplFromInputStreamParams(const InputStreamParams& aParams, CreateBlobImplFromBlobData(const BlobData& aBlobData,
CreateBlobImplMetadata& aMetadata) CreateBlobImplMetadata& aMetadata)
{ {
MOZ_ASSERT(gProcessType == GeckoProcessType_Default); MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
nsRefPtr<FileImpl> blobImpl; nsRefPtr<FileImpl> blobImpl;
switch (aParams.type()) { switch (aBlobData.type()) {
case InputStreamParams::TStringInputStreamParams: { case BlobData::TnsID: {
const StringInputStreamParams& params = blobImpl = CreateBlobImpl(aBlobData.get_nsID(), aMetadata);
aParams.get_StringInputStreamParams();
blobImpl = CreateBlobImplFromParams(params, aMetadata);
break; break;
} }
case InputStreamParams::TFileInputStreamParams: { case BlobData::TArrayOfuint8_t: {
ASSERT_UNLESS_FUZZING(); blobImpl = CreateBlobImpl(aBlobData.get_ArrayOfuint8_t(), aMetadata);
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);
break; break;
} }
case InputStreamParams::TRemoteInputStreamParams: { case BlobData::Tintptr_t: {
if (NS_WARN_IF(!aMetadata.mHasRecursed)) { blobImpl = CreateBlobImpl(aBlobData.get_intptr_t(), aMetadata);
ASSERT_UNLESS_FUZZING();
return nullptr;
}
const RemoteInputStreamParams& params =
aParams.get_RemoteInputStreamParams();
blobImpl = CreateBlobImplFromParams(params, aMetadata);
break; break;
} }
case InputStreamParams::TSameProcessInputStreamParams: { case BlobData::TArrayOfBlobData: {
if (NS_WARN_IF(!aMetadata.mIsSameProcessActor)) { blobImpl = CreateBlobImpl(aBlobData.get_ArrayOfBlobData(), aMetadata);
ASSERT_UNLESS_FUZZING();
return nullptr;
}
const SameProcessInputStreamParams& params =
aParams.get_SameProcessInputStreamParams();
blobImpl = CreateBlobImplFromParams(params, aMetadata);
break; break;
} }
@ -1047,34 +1013,17 @@ CreateBlobImplFromInputStreamParams(const InputStreamParams& aParams,
} }
already_AddRefed<FileImpl> already_AddRefed<FileImpl>
CreateBlobImplFromParams(const MultiplexInputStreamParams& aParams, CreateBlobImpl(const nsTArray<BlobData>& aBlobDatas,
CreateBlobImplMetadata& aMetadata) CreateBlobImplMetadata& aMetadata)
{ {
MOZ_ASSERT(gProcessType == GeckoProcessType_Default); 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<InputStreamParams>& streams = aParams.streams();
// Special case for a multipart blob with only one part. // Special case for a multipart blob with only one part.
if (streams.Length() == 1) { if (aBlobDatas.Length() == 1) {
const InputStreamParams& params = streams[0]; const BlobData& blobData = aBlobDatas[0];
nsRefPtr<FileImpl> blobImpl = nsRefPtr<FileImpl> blobImpl =
CreateBlobImplFromInputStreamParams(params, aMetadata); CreateBlobImplFromBlobData(blobData, aMetadata);
if (NS_WARN_IF(!blobImpl)) { if (NS_WARN_IF(!blobImpl)) {
return nullptr; return nullptr;
} }
@ -1087,7 +1036,7 @@ CreateBlobImplFromParams(const MultiplexInputStreamParams& aParams,
} }
FallibleTArray<nsRefPtr<FileImpl>> fallibleBlobImpls; FallibleTArray<nsRefPtr<FileImpl>> fallibleBlobImpls;
if (NS_WARN_IF(!fallibleBlobImpls.SetLength(streams.Length()))) { if (NS_WARN_IF(!fallibleBlobImpls.SetLength(aBlobDatas.Length()))) {
return nullptr; return nullptr;
} }
@ -1097,11 +1046,13 @@ CreateBlobImplFromParams(const MultiplexInputStreamParams& aParams,
const bool hasRecursed = aMetadata.mHasRecursed; const bool hasRecursed = aMetadata.mHasRecursed;
aMetadata.mHasRecursed = true; aMetadata.mHasRecursed = true;
for (uint32_t count = streams.Length(), index = 0; index < count; index++) { for (uint32_t count = aBlobDatas.Length(), index = 0;
const InputStreamParams& params = streams[index]; index < count;
index++) {
const BlobData& blobData = aBlobDatas[index];
nsRefPtr<FileImpl>& blobImpl = blobImpls[index]; nsRefPtr<FileImpl>& blobImpl = blobImpls[index];
blobImpl = CreateBlobImplFromParams(params, aMetadata); blobImpl = CreateBlobImplFromBlobData(blobData, aMetadata);
if (NS_WARN_IF(!blobImpl)) { if (NS_WARN_IF(!blobImpl)) {
return nullptr; return nullptr;
} }
@ -1126,18 +1077,17 @@ CreateBlobImplFromParams(const MultiplexInputStreamParams& aParams,
} }
already_AddRefed<FileImpl> already_AddRefed<FileImpl>
CreateBlobImplFromParams(const ParentBlobConstructorParams& aParams, CreateBlobImpl(const ParentBlobConstructorParams& aParams,
bool aIsSameProcessActor) const BlobData& aBlobData,
bool aIsSameProcessActor)
{ {
MOZ_ASSERT(gProcessType == GeckoProcessType_Default); MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
MOZ_ASSERT(aParams.blobParams().type() == MOZ_ASSERT(aParams.blobParams().type() ==
AnyBlobConstructorParams::TNormalBlobConstructorParams || AnyBlobConstructorParams::TNormalBlobConstructorParams ||
aParams.blobParams().type() == aParams.blobParams().type() ==
AnyBlobConstructorParams::TFileBlobConstructorParams); AnyBlobConstructorParams::TFileBlobConstructorParams);
MOZ_ASSERT(aParams.optionalInputStreamParams().type() ==
OptionalInputStreamParams::TInputStreamParams);
CreateBlobImplMetadata metadata; CreateBlobImplMetadata metadata(aIsSameProcessActor);
if (aParams.blobParams().type() == if (aParams.blobParams().type() ==
AnyBlobConstructorParams::TNormalBlobConstructorParams) { AnyBlobConstructorParams::TNormalBlobConstructorParams) {
@ -1171,16 +1121,71 @@ CreateBlobImplFromParams(const ParentBlobConstructorParams& aParams,
metadata.mLastModifiedDate = params.modDate(); metadata.mLastModifiedDate = params.modDate();
} }
metadata.mIsSameProcessActor = aIsSameProcessActor;
const InputStreamParams& inputStreamParams =
aParams.optionalInputStreamParams().get_InputStreamParams();
nsRefPtr<FileImpl> blobImpl = nsRefPtr<FileImpl> blobImpl =
CreateBlobImplFromInputStreamParams(inputStreamParams, metadata); CreateBlobImplFromBlobData(aBlobData, metadata);
return blobImpl.forget(); return blobImpl.forget();
} }
void
BlobDataFromBlobImpl(FileImpl* aBlobImpl, BlobData& aBlobData)
{
MOZ_ASSERT(gProcessType != GeckoProcessType_Default);
MOZ_ASSERT(aBlobImpl);
const nsTArray<nsRefPtr<FileImpl>>* subBlobs = aBlobImpl->GetSubBlobImpls();
if (subBlobs) {
aBlobData = nsTArray<BlobData>();
nsTArray<BlobData>& 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<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlobImpl);
if (remoteBlob) {
BlobChild* actor = remoteBlob->GetBlobChild();
MOZ_ASSERT(actor);
aBlobData = actor->ParentID();
return;
}
MOZ_ASSERT(aBlobImpl->IsMemoryFile());
nsCOMPtr<nsIInputStream> inputStream;
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
aBlobImpl->GetInternalStream(getter_AddRefs(inputStream))));
DebugOnly<bool> 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<uint8_t>();
nsTArray<uint8_t>& blobData = aBlobData.get_ArrayOfuint8_t();
blobData.SetLength(size_t(available));
uint32_t readCount;
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
inputStream->Read(reinterpret_cast<char*>(blobData.Elements()),
uint32_t(available),
&readCount)));
}
} // anonymous namespace } // anonymous namespace
StaticAutoPtr<BlobParent::IDTable> BlobParent::sIDTable; StaticAutoPtr<BlobParent::IDTable> BlobParent::sIDTable;
@ -1548,6 +1553,9 @@ protected:
BlobChild* mActor; BlobChild* mActor;
nsCOMPtr<nsIEventTarget> mActorTarget; nsCOMPtr<nsIEventTarget> mActorTarget;
nsRefPtr<FileImpl> mSameProcessFileImpl;
const bool mIsSlice; const bool mIsSlice;
public: public:
@ -1563,6 +1571,20 @@ public:
const nsAString& aContentType, const nsAString& aContentType,
uint64_t aLength); 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. // For mystery blobs.
explicit explicit
RemoteBlobImpl(BlobChild* aActor); RemoteBlobImpl(BlobChild* aActor);
@ -1853,6 +1875,38 @@ RemoteBlobImpl::RemoteBlobImpl(BlobChild* aActor,
CommonInit(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:: BlobChild::
RemoteBlobImpl::RemoteBlobImpl(BlobChild* aActor) RemoteBlobImpl::RemoteBlobImpl(BlobChild* aActor)
: FileImplBase(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX) : FileImplBase(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX)
@ -1954,6 +2008,13 @@ RemoteBlobImpl::GetMozFullPathInternal(nsAString& aFilePath,
MOZ_CRASH("Not implemented!"); MOZ_CRASH("Not implemented!");
} }
if (mSameProcessFileImpl) {
MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
mSameProcessFileImpl->GetMozFullPathInternal(aFilePath, aRv);
return;
}
if (!mActor) { if (!mActor) {
aRv.Throw(NS_ERROR_UNEXPECTED); aRv.Throw(NS_ERROR_UNEXPECTED);
return; return;
@ -1976,9 +2037,18 @@ RemoteBlobImpl::CreateSlice(uint64_t aStart,
ErrorResult& aRv) ErrorResult& aRv)
{ {
// May be called on any thread. // May be called on any thread.
nsRefPtr<RemoteBlobSliceImpl> slice = if (mSameProcessFileImpl) {
new RemoteBlobSliceImpl(this, aStart, aLength, aContentType); MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
return slice.forget();
return mSameProcessFileImpl->CreateSlice(aStart,
aLength,
aContentType,
aRv);
}
nsRefPtr<RemoteBlobSliceImpl> slice =
new RemoteBlobSliceImpl(this, aStart, aLength, aContentType);
return slice.forget();
} }
nsresult nsresult
@ -1986,6 +2056,22 @@ BlobChild::
RemoteBlobImpl::GetInternalStream(nsIInputStream** aStream) RemoteBlobImpl::GetInternalStream(nsIInputStream** aStream)
{ {
// May be called on any thread. // May be called on any thread.
if (mSameProcessFileImpl) {
MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
nsCOMPtr<nsIInputStream> realStream;
nsresult rv =
mSameProcessFileImpl->GetInternalStream(getter_AddRefs(realStream));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsRefPtr<BlobInputStreamTether> tether =
new BlobInputStreamTether(realStream, mSameProcessFileImpl);
tether.forget(aStream);
return NS_OK;
}
nsRefPtr<CreateStreamHelper> helper = new CreateStreamHelper(this); nsRefPtr<CreateStreamHelper> helper = new CreateStreamHelper(this);
return helper->GetStream(aStream); return helper->GetStream(aStream);
} }
@ -1998,6 +2084,12 @@ RemoteBlobImpl::GetFileId()
MOZ_CRASH("Not implemented!"); MOZ_CRASH("Not implemented!");
} }
if (mSameProcessFileImpl) {
MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
return mSameProcessFileImpl->GetFileId();
}
int64_t fileId; int64_t fileId;
if (mActor && mActor->SendGetFileId(&fileId)) { if (mActor && mActor->SendGetFileId(&fileId)) {
return fileId; return fileId;
@ -2209,8 +2301,7 @@ RemoteBlobSliceImpl::GetBlobChild()
id /* id */, id /* id */,
mStart /* begin */, mStart /* begin */,
mStart + mLength /* end */, mStart + mLength /* end */,
mContentType /* contentType */), mContentType /* contentType */));
void_t() /* optionalInputStream */);
if (nsIContentChild* contentManager = baseActor->GetContentManager()) { if (nsIContentChild* contentManager = baseActor->GetContentManager()) {
mActor = SendSliceConstructor(contentManager, this, params); mActor = SendSliceConstructor(contentManager, this, params);
@ -2648,6 +2739,8 @@ BlobChild::CommonInit(const ChildBlobConstructorParams& aParams)
AnyBlobConstructorParams::Type paramsType = blobParams.type(); AnyBlobConstructorParams::Type paramsType = blobParams.type();
MOZ_ASSERT(paramsType != AnyBlobConstructorParams::T__None && MOZ_ASSERT(paramsType != AnyBlobConstructorParams::T__None &&
paramsType !=
AnyBlobConstructorParams::TSlicedBlobConstructorParams &&
paramsType != paramsType !=
AnyBlobConstructorParams::TKnownBlobConstructorParams); AnyBlobConstructorParams::TKnownBlobConstructorParams);
@ -2673,6 +2766,44 @@ BlobChild::CommonInit(const ChildBlobConstructorParams& aParams)
break; break;
} }
case AnyBlobConstructorParams::TSameProcessBlobConstructorParams: {
MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
const SameProcessBlobConstructorParams& params =
blobParams.get_SameProcessBlobConstructorParams();
MOZ_ASSERT(params.addRefedFileImpl());
nsRefPtr<FileImpl> blobImpl =
dont_AddRef(reinterpret_cast<FileImpl*>(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: { case AnyBlobConstructorParams::TMysteryBlobConstructorParams: {
remoteBlob = new RemoteBlobImpl(this); remoteBlob = new RemoteBlobImpl(this);
break; 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)))) { if (NS_WARN_IF(NS_FAILED(aBlobImpl->SetMutable(false)))) {
return nullptr; return nullptr;
} }
@ -2808,40 +2939,55 @@ BlobChild::GetOrCreateFromImpl(ChildManagerType* aManager,
AnyBlobConstructorParams blobParams; AnyBlobConstructorParams blobParams;
nsString contentType; nsCOMPtr<nsIInputStream> snapshotInputStream;
aBlobImpl->GetType(contentType);
ErrorResult rv; if (gProcessType == GeckoProcessType_Default) {
uint64_t length = aBlobImpl->GetSize(rv); nsCOMPtr<PIFileImplSnapshot> snapshot = do_QueryInterface(aBlobImpl);
MOZ_ASSERT(!rv.Failed()); if (snapshot) {
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
nsCOMPtr<nsIInputStream> stream; aBlobImpl->GetInternalStream(getter_AddRefs(snapshotInputStream))));
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);
} }
InputStreamParams inputStreamParams; if (gProcessType == GeckoProcessType_Default && !snapshotInputStream) {
nsRefPtr<FileImpl> sameProcessImpl = aBlobImpl;
auto addRefedFileImpl =
reinterpret_cast<intptr_t>(sameProcessImpl.forget().take());
nsTArray<FileDescriptor> fds; blobParams = SameProcessBlobConstructorParams(addRefedFileImpl);
SerializeInputStream(stream, inputStreamParams, fds); } else {
BlobData blobData;
if (snapshotInputStream) {
blobData =
reinterpret_cast<intptr_t>(snapshotInputStream.forget().take());
} else {
BlobDataFromBlobImpl(aBlobImpl, blobData);
}
MOZ_ASSERT(inputStreamParams.type() != InputStreamParams::T__None); nsString contentType;
MOZ_ASSERT(fds.IsEmpty()); 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); BlobChild* actor = new BlobChild(aManager, aBlobImpl);
ParentBlobConstructorParams params(blobParams, inputStreamParams); ParentBlobConstructorParams params(blobParams);
if (NS_WARN_IF(!aManager->SendPBlobConstructor(actor, params))) { if (NS_WARN_IF(!aManager->SendPBlobConstructor(actor, params))) {
BlobChild::Destroy(actor); BlobChild::Destroy(actor);
@ -2865,6 +3011,7 @@ BlobChild::CreateFromParams(ChildManagerType* aManager,
switch (blobParams.type()) { switch (blobParams.type()) {
case AnyBlobConstructorParams::TNormalBlobConstructorParams: case AnyBlobConstructorParams::TNormalBlobConstructorParams:
case AnyBlobConstructorParams::TFileBlobConstructorParams: case AnyBlobConstructorParams::TFileBlobConstructorParams:
case AnyBlobConstructorParams::TSameProcessBlobConstructorParams:
case AnyBlobConstructorParams::TMysteryBlobConstructorParams: { case AnyBlobConstructorParams::TMysteryBlobConstructorParams: {
return new BlobChild(aManager, aParams); return new BlobChild(aManager, aParams);
} }
@ -2896,8 +3043,6 @@ BlobChild::SendSliceConstructor(ChildManagerType* aManager,
MOZ_ASSERT(aRemoteBlobSliceImpl); MOZ_ASSERT(aRemoteBlobSliceImpl);
MOZ_ASSERT(aParams.blobParams().type() == MOZ_ASSERT(aParams.blobParams().type() ==
AnyBlobConstructorParams::TSlicedBlobConstructorParams); AnyBlobConstructorParams::TSlicedBlobConstructorParams);
MOZ_ASSERT(aParams.optionalInputStreamParams().type() ==
OptionalInputStreamParams::Tvoid_t);
const nsID& id = aParams.blobParams().get_SlicedBlobConstructorParams().id(); const nsID& id = aParams.blobParams().get_SlicedBlobConstructorParams().id();
@ -2933,8 +3078,7 @@ BlobChild::MaybeGetActorFromRemoteBlob(nsIRemoteBlob* aRemoteBlob,
actor = new BlobChild(aManager, actor); actor = new BlobChild(aManager, actor);
ParentBlobConstructorParams params( ParentBlobConstructorParams params(
KnownBlobConstructorParams(actor->ParentID()) /* blobParams */, KnownBlobConstructorParams(actor->ParentID()));
void_t() /* optionalInputStream */);
aManager->SendPBlobConstructor(actor, params); aManager->SendPBlobConstructor(actor, params);
@ -2963,8 +3107,7 @@ BlobChild::MaybeGetActorFromRemoteBlob(nsIRemoteBlob* aRemoteBlob,
actor = new BlobChild(aManager, actor); actor = new BlobChild(aManager, actor);
ParentBlobConstructorParams params( ParentBlobConstructorParams params(
KnownBlobConstructorParams(actor->ParentID()) /* blobParams */, KnownBlobConstructorParams(actor->ParentID()));
void_t() /* optionalInputStream */);
aManager->SendPBlobConstructor(actor, params); aManager->SendPBlobConstructor(actor, params);
@ -3019,8 +3162,11 @@ BlobChild::SetMysteryBlobInfo(const nsString& aName,
mBlobImpl->SetLazyData(aName, aContentType, aLength, aLastModifiedDate); mBlobImpl->SetLazyData(aName, aContentType, aLength, aLastModifiedDate);
FileBlobConstructorParams params(aName, aContentType, aLength, FileBlobConstructorParams params(aName,
aLastModifiedDate); aContentType,
aLength,
aLastModifiedDate,
void_t() /* optionalBlobData */);
return SendResolveMystery(params); return SendResolveMystery(params);
} }
@ -3036,7 +3182,9 @@ BlobChild::SetMysteryBlobInfo(const nsString& aContentType, uint64_t aLength)
mBlobImpl->SetLazyData(voidString, aContentType, aLength, UINT64_MAX); mBlobImpl->SetLazyData(voidString, aContentType, aLength, UINT64_MAX);
NormalBlobConstructorParams params(aContentType, aLength); NormalBlobConstructorParams params(aContentType,
aLength,
void_t() /* optionalBlobData */);
return SendResolveMystery(params); 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)))) { if (NS_WARN_IF(NS_FAILED(aBlobImpl->SetMutable(false)))) {
return nullptr; return nullptr;
} }
const bool isSameProcessActor = ActorManagerIsSameProcess(aManager);
AnyBlobConstructorParams blobParams; AnyBlobConstructorParams blobParams;
if (aBlobImpl->IsSizeUnknown() || aBlobImpl->IsDateUnknown()) { bool isSnapshot;
// 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 if (isSameProcessActor) {
// the other side. nsCOMPtr<PIFileImplSnapshot> snapshot = do_QueryInterface(aBlobImpl);
blobParams = MysteryBlobConstructorParams(); isSnapshot = !!snapshot;
} else { } else {
nsString contentType; isSnapshot = false;
aBlobImpl->GetType(contentType); }
ErrorResult rv; if (isSameProcessActor && !isSnapshot) {
uint64_t length = aBlobImpl->GetSize(rv); nsRefPtr<FileImpl> sameProcessImpl = aBlobImpl;
MOZ_ASSERT(!rv.Failed()); auto addRefedFileImpl =
reinterpret_cast<intptr_t>(sameProcessImpl.forget().take());
if (aBlobImpl->IsFile()) { blobParams = SameProcessBlobConstructorParams(addRefedFileImpl);
nsString name; } else {
aBlobImpl->GetName(name); 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()); MOZ_ASSERT(!rv.Failed());
blobParams = if (aBlobImpl->IsFile()) {
FileBlobConstructorParams(name, contentType, length, modDate); nsString name;
} else { aBlobImpl->GetName(name);
blobParams = NormalBlobConstructorParams(contentType, length);
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::TNormalBlobConstructorParams:
case AnyBlobConstructorParams::TFileBlobConstructorParams: { case AnyBlobConstructorParams::TFileBlobConstructorParams: {
if (aParams.optionalInputStreamParams().type() != const OptionalBlobData& optionalBlobData =
OptionalInputStreamParams::TInputStreamParams) { blobParams.type() ==
AnyBlobConstructorParams::TNormalBlobConstructorParams ?
blobParams.get_NormalBlobConstructorParams().optionalBlobData() :
blobParams.get_FileBlobConstructorParams().optionalBlobData();
if (NS_WARN_IF(optionalBlobData.type() != OptionalBlobData::TBlobData)) {
ASSERT_UNLESS_FUZZING(); ASSERT_UNLESS_FUZZING();
return nullptr; return nullptr;
} }
nsRefPtr<FileImpl> blobImpl = nsRefPtr<FileImpl> blobImpl =
CreateBlobImplFromParams(aParams, ActorManagerIsSameProcess(aManager)); CreateBlobImpl(aParams,
optionalBlobData.get_BlobData(),
ActorManagerIsSameProcess(aManager));
if (NS_WARN_IF(!blobImpl)) { if (NS_WARN_IF(!blobImpl)) {
ASSERT_UNLESS_FUZZING(); ASSERT_UNLESS_FUZZING();
return nullptr; return nullptr;
@ -3424,12 +3598,6 @@ BlobParent::CreateFromParams(ParentManagerType* aManager,
} }
case AnyBlobConstructorParams::TSlicedBlobConstructorParams: { case AnyBlobConstructorParams::TSlicedBlobConstructorParams: {
if (aParams.optionalInputStreamParams().type() !=
OptionalInputStreamParams::Tvoid_t) {
ASSERT_UNLESS_FUZZING();
return nullptr;
}
const SlicedBlobConstructorParams& params = const SlicedBlobConstructorParams& params =
blobParams.get_SlicedBlobConstructorParams(); blobParams.get_SlicedBlobConstructorParams();
@ -3472,12 +3640,6 @@ BlobParent::CreateFromParams(ParentManagerType* aManager,
} }
case AnyBlobConstructorParams::TKnownBlobConstructorParams: { case AnyBlobConstructorParams::TKnownBlobConstructorParams: {
if (aParams.optionalInputStreamParams().type() !=
OptionalInputStreamParams::Tvoid_t) {
ASSERT_UNLESS_FUZZING();
return nullptr;
}
const KnownBlobConstructorParams& params = const KnownBlobConstructorParams& params =
blobParams.get_KnownBlobConstructorParams(); blobParams.get_KnownBlobConstructorParams();
@ -3494,6 +3656,29 @@ BlobParent::CreateFromParams(ParentManagerType* aManager,
return new BlobParent(aManager, blobImpl, idTableEntry); 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<FileImpl> blobImpl =
dont_AddRef(reinterpret_cast<FileImpl*>(params.addRefedFileImpl()));
MOZ_ASSERT(blobImpl);
nsID id;
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(gUUIDGenerator->GenerateUUIDInPlace(&id)));
nsRefPtr<IDTableEntry> idTableEntry =
IDTableEntry::Create(id, ActorManagerProcessID(aManager), blobImpl);
MOZ_ASSERT(idTableEntry);
return new BlobParent(aManager, blobImpl, idTableEntry);
}
default: default:
MOZ_CRASH("Unknown params!"); MOZ_CRASH("Unknown params!");
} }

View File

@ -5,7 +5,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
include protocol PBlob; include protocol PBlob;
include InputStreamParams;
using struct mozilla::void_t using struct mozilla::void_t
from "ipc/IPCMessageUtils.h"; from "ipc/IPCMessageUtils.h";
@ -13,6 +12,9 @@ using struct mozilla::void_t
using struct mozilla::SerializedStructuredCloneBuffer using struct mozilla::SerializedStructuredCloneBuffer
from "ipc/IPCMessageUtils.h"; from "ipc/IPCMessageUtils.h";
using struct nsID
from "nsID.h";
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
@ -28,10 +30,35 @@ struct ClonedMessageData
PBlob[] blobs; 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 struct NormalBlobConstructorParams
{ {
nsString contentType; nsString contentType;
uint64_t length; 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 struct FileBlobConstructorParams
@ -40,6 +67,10 @@ struct FileBlobConstructorParams
nsString contentType; nsString contentType;
uint64_t length; uint64_t length;
uint64_t modDate; 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 struct SlicedBlobConstructorParams
@ -61,11 +92,20 @@ struct KnownBlobConstructorParams
nsID id; 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 union AnyBlobConstructorParams
{ {
// These types may be sent to/from parent and child. // These types may be sent to/from parent and child.
NormalBlobConstructorParams; NormalBlobConstructorParams;
FileBlobConstructorParams; FileBlobConstructorParams;
SameProcessBlobConstructorParams;
// This type may only be sent from parent to child. // This type may only be sent from parent to child.
MysteryBlobConstructorParams; MysteryBlobConstructorParams;
@ -87,14 +127,6 @@ struct ParentBlobConstructorParams
{ {
// May not be MysteryBlobConstructorParams. // May not be MysteryBlobConstructorParams.
AnyBlobConstructorParams blobParams; 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 union BlobConstructorParams

View File

@ -2,13 +2,13 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * 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 PBlob;
include protocol PFileDescriptorSet; include protocol PFileDescriptorSet;
using struct nsID include DOMTypes;
from "nsID.h";
using struct mozilla::void_t
from "ipc/IPCMessageUtils.h";
namespace mozilla { namespace mozilla {
namespace ipc { namespace ipc {

View File

@ -18,6 +18,8 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm"); Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.importGlobalProperties(["File"]);
// Allow stuff from this scope to be accessed from non-privileged scopes. This // Allow stuff from this scope to be accessed from non-privileged scopes. This
// would crash if used outside of automation. // would crash if used outside of automation.
Cu.forcePermissiveCOWs(); Cu.forcePermissiveCOWs();
@ -1877,6 +1879,10 @@ SpecialPowersAPI.prototype = {
let msg = { op: op, uri: uri, appId: appId, inBrowser: inBrowser, id: id }; let msg = { op: op, uri: uri, appId: appId, inBrowser: inBrowser, id: id };
this._sendAsyncMessage(messageTopic, msg); this._sendAsyncMessage(messageTopic, msg);
}, },
createDOMFile: function(path, options) {
return new File(path, options);
},
}; };
this.SpecialPowersAPI = SpecialPowersAPI; this.SpecialPowersAPI = SpecialPowersAPI;