зеркало из https://github.com/mozilla/gecko-dev.git
Bug 982779 - Ensure that child->parent IPC blobs are never mysterious, r=baku.
This commit is contained in:
Родитель
727cf86888
Коммит
e7d0d6522b
|
@ -34,6 +34,7 @@
|
|||
#include "nsWrapperCache.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
|
||||
class nsDOMMultipartFile;
|
||||
class nsIFile;
|
||||
class nsIInputStream;
|
||||
class nsIClassInfo;
|
||||
|
@ -42,6 +43,8 @@ class nsDOMFileBase : public nsIDOMFile,
|
|||
public nsIXHRSendable,
|
||||
public nsIMutable
|
||||
{
|
||||
friend class nsDOMMultipartFile;
|
||||
|
||||
public:
|
||||
typedef mozilla::dom::indexedDB::FileInfo FileInfo;
|
||||
|
||||
|
@ -361,8 +364,9 @@ public:
|
|||
nsDOMMemoryFile(void *aMemoryBuffer,
|
||||
uint64_t aLength,
|
||||
const nsAString& aName,
|
||||
const nsAString& aContentType)
|
||||
: nsDOMFile(aName, aContentType, aLength, UINT64_MAX),
|
||||
const nsAString& aContentType,
|
||||
uint64_t aLastModifiedDate)
|
||||
: nsDOMFile(aName, aContentType, aLength, aLastModifiedDate),
|
||||
mDataOwner(new DataOwner(aMemoryBuffer, aLength))
|
||||
{
|
||||
NS_ASSERTION(mDataOwner && mDataOwner->mData, "must have data");
|
||||
|
|
|
@ -27,26 +27,6 @@ NS_IMPL_ISUPPORTS_INHERITED(nsDOMMultipartFile, nsDOMFile,
|
|||
NS_IMETHODIMP
|
||||
nsDOMMultipartFile::GetSize(uint64_t* aLength)
|
||||
{
|
||||
if (mLength == UINT64_MAX) {
|
||||
CheckedUint64 length = 0;
|
||||
|
||||
uint32_t i;
|
||||
uint32_t len = mBlobs.Length();
|
||||
for (i = 0; i < len; i++) {
|
||||
nsIDOMBlob* blob = mBlobs.ElementAt(i).get();
|
||||
uint64_t l = 0;
|
||||
|
||||
nsresult rv = blob->GetSize(&l);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
length += l;
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE(length.isValid(), NS_ERROR_FAILURE);
|
||||
|
||||
mLength = length.value();
|
||||
}
|
||||
|
||||
*aLength = mLength;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -214,6 +194,8 @@ nsDOMMultipartFile::InitBlob(JSContext* aCx,
|
|||
return ParseBlobArrayArgument(aCx, aArgv[0], nativeEOL, aUnwrapFunc);
|
||||
}
|
||||
|
||||
SetLengthAndModifiedDate();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -279,9 +261,48 @@ nsDOMMultipartFile::ParseBlobArrayArgument(JSContext* aCx, JS::Value& aValue,
|
|||
}
|
||||
|
||||
mBlobs = blobSet.GetBlobs();
|
||||
|
||||
SetLengthAndModifiedDate();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMMultipartFile::SetLengthAndModifiedDate()
|
||||
{
|
||||
MOZ_ASSERT(mLength == UINT64_MAX);
|
||||
MOZ_ASSERT(mLastModificationDate == UINT64_MAX);
|
||||
|
||||
uint64_t totalLength = 0;
|
||||
|
||||
for (uint32_t index = 0, count = mBlobs.Length(); index < count; index++) {
|
||||
nsCOMPtr<nsIDOMBlob>& blob = mBlobs[index];
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
// XXX This is only safe so long as all blob implementations in our tree
|
||||
// inherit nsDOMFileBase.
|
||||
const auto* blobBase = static_cast<nsDOMFileBase*>(blob.get());
|
||||
|
||||
MOZ_ASSERT(!blobBase->IsSizeUnknown());
|
||||
MOZ_ASSERT(!blobBase->IsDateUnknown());
|
||||
}
|
||||
#endif
|
||||
|
||||
uint64_t subBlobLength;
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blob->GetSize(&subBlobLength)));
|
||||
|
||||
MOZ_ASSERT(UINT64_MAX - subBlobLength >= totalLength);
|
||||
totalLength += subBlobLength;
|
||||
}
|
||||
|
||||
mLength = totalLength;
|
||||
|
||||
if (mIsFile) {
|
||||
mLastModificationDate = PR_Now();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMMultipartFile::GetMozFullPathInternal(nsAString &aFilename)
|
||||
{
|
||||
|
@ -374,7 +395,18 @@ nsDOMMultipartFile::InitChromeFile(JSContext* aCx,
|
|||
file->GetLeafName(mName);
|
||||
}
|
||||
|
||||
blob = new nsDOMFileFile(file);
|
||||
nsRefPtr<nsDOMFileFile> domFile = new nsDOMFileFile(file);
|
||||
|
||||
// Pre-cache size.
|
||||
uint64_t unused;
|
||||
rv = domFile->GetSize(&unused);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Pre-cache modified date.
|
||||
rv = domFile->GetMozLastModifiedDate(&unused);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
blob = domFile.forget();
|
||||
}
|
||||
|
||||
// XXXkhuey this is terrible
|
||||
|
@ -386,6 +418,8 @@ nsDOMMultipartFile::InitChromeFile(JSContext* aCx,
|
|||
blobSet.AppendBlob(blob);
|
||||
mBlobs = blobSet.GetBlobs();
|
||||
|
||||
SetLengthAndModifiedDate();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ public:
|
|||
mBlobs(aBlobs),
|
||||
mIsFromNsiFile(false)
|
||||
{
|
||||
SetLengthAndModifiedDate();
|
||||
}
|
||||
|
||||
// Create as a blob
|
||||
|
@ -41,6 +42,7 @@ public:
|
|||
mBlobs(aBlobs),
|
||||
mIsFromNsiFile(false)
|
||||
{
|
||||
SetLengthAndModifiedDate();
|
||||
}
|
||||
|
||||
// Create as a file to be later initialized
|
||||
|
@ -109,6 +111,8 @@ protected:
|
|||
nsresult ParseBlobArrayArgument(JSContext* aCx, JS::Value& aValue,
|
||||
bool aNativeEOL, UnwrapFuncPtr aUnwrapFunc);
|
||||
|
||||
void SetLengthAndModifiedDate();
|
||||
|
||||
nsTArray<nsCOMPtr<nsIDOMBlob> > mBlobs;
|
||||
bool mIsFromNsiFile;
|
||||
};
|
||||
|
@ -170,7 +174,7 @@ protected:
|
|||
// and put it on the stack
|
||||
|
||||
nsCOMPtr<nsIDOMBlob> blob =
|
||||
new nsDOMMemoryFile(mData, mDataLen, EmptyString(), EmptyString());
|
||||
new nsDOMMemoryFile(mData, mDataLen, EmptyString());
|
||||
mBlobs.AppendElement(blob);
|
||||
mData = nullptr; // The nsDOMMemoryFile takes ownership of the buffer
|
||||
mDataLen = 0;
|
||||
|
|
|
@ -591,7 +591,7 @@ HTMLCanvasElement::MozGetAsFileImpl(const nsAString& aName,
|
|||
|
||||
// The DOMFile takes ownership of the buffer
|
||||
nsRefPtr<nsDOMMemoryFile> file =
|
||||
new nsDOMMemoryFile(imgData, (uint32_t)imgSize, aName, type);
|
||||
new nsDOMMemoryFile(imgData, (uint32_t)imgSize, aName, type, PR_Now());
|
||||
|
||||
file.forget(aResult);
|
||||
return NS_OK;
|
||||
|
|
|
@ -1821,10 +1821,15 @@ BlobParent::Create(ContentParent* aManager,
|
|||
|
||||
const ChildBlobConstructorParams& blobParams = aParams.blobParams();
|
||||
|
||||
MOZ_ASSERT(blobParams.type() !=
|
||||
ChildBlobConstructorParams::TMysteryBlobConstructorParams);
|
||||
|
||||
switch (blobParams.type()) {
|
||||
case ChildBlobConstructorParams::TMysteryBlobConstructorParams:
|
||||
return nullptr;
|
||||
|
||||
case ChildBlobConstructorParams::TNormalBlobConstructorParams:
|
||||
case ChildBlobConstructorParams::TFileBlobConstructorParams:
|
||||
case ChildBlobConstructorParams::TMysteryBlobConstructorParams:
|
||||
return new BlobParent(aManager, aParams);
|
||||
|
||||
case ChildBlobConstructorParams::TSlicedBlobConstructorParams: {
|
||||
|
|
|
@ -876,43 +876,6 @@ ContentChild::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
|
|||
return actor;
|
||||
}
|
||||
|
||||
// XXX This is only safe so long as all blob implementations in our tree
|
||||
// inherit nsDOMFileBase. If that ever changes then this will need to grow
|
||||
// a real interface or something.
|
||||
const nsDOMFileBase* blob = static_cast<nsDOMFileBase*>(aBlob);
|
||||
|
||||
// We often pass blobs that are multipart but that only contain one sub-blob
|
||||
// (WebActivities does this a bunch). Unwrap to reduce the number of actors
|
||||
// that we have to maintain.
|
||||
const nsTArray<nsCOMPtr<nsIDOMBlob> >* subBlobs = blob->GetSubBlobs();
|
||||
if (subBlobs && subBlobs->Length() == 1) {
|
||||
const nsCOMPtr<nsIDOMBlob>& subBlob = subBlobs->ElementAt(0);
|
||||
MOZ_ASSERT(subBlob);
|
||||
|
||||
// We can only take this shortcut if the multipart and the sub-blob are both
|
||||
// Blob objects or both File objects.
|
||||
nsCOMPtr<nsIDOMFile> multipartBlobAsFile = do_QueryInterface(aBlob);
|
||||
nsCOMPtr<nsIDOMFile> subBlobAsFile = do_QueryInterface(subBlob);
|
||||
if (!multipartBlobAsFile == !subBlobAsFile) {
|
||||
// The wrapping was unnecessary, see if we can simply pass an existing
|
||||
// remote blob.
|
||||
if (nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(subBlob)) {
|
||||
BlobChild* actor =
|
||||
static_cast<BlobChild*>(
|
||||
static_cast<PBlobChild*>(remoteBlob->GetPBlob()));
|
||||
MOZ_ASSERT(actor);
|
||||
return actor;
|
||||
}
|
||||
|
||||
// No need to add a reference here since the original blob must have a
|
||||
// strong reference in the caller and it must also have a strong reference
|
||||
// to this sub-blob.
|
||||
aBlob = subBlob;
|
||||
blob = static_cast<nsDOMFileBase*>(aBlob);
|
||||
subBlobs = blob->GetSubBlobs();
|
||||
}
|
||||
}
|
||||
|
||||
// All blobs shared between processes must be immutable.
|
||||
nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(aBlob);
|
||||
if (!mutableBlob || NS_FAILED(mutableBlob->SetMutable(false))) {
|
||||
|
@ -920,56 +883,59 @@ ContentChild::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
// XXX This is only safe so long as all blob implementations in our tree
|
||||
// inherit nsDOMFileBase. If that ever changes then this will need to
|
||||
// grow a real interface or something.
|
||||
const auto* blob = static_cast<nsDOMFileBase*>(aBlob);
|
||||
|
||||
MOZ_ASSERT(!blob->IsSizeUnknown());
|
||||
MOZ_ASSERT(!blob->IsDateUnknown());
|
||||
}
|
||||
#endif
|
||||
|
||||
ParentBlobConstructorParams params;
|
||||
|
||||
if (blob->IsSizeUnknown() || blob->IsDateUnknown()) {
|
||||
// We don't want to call GetSize or GetLastModifiedDate
|
||||
// yet since that may stat a file on the main thread
|
||||
// here. Instead we'll learn the size lazily from the
|
||||
// other process.
|
||||
params.blobParams() = MysteryBlobConstructorParams();
|
||||
params.optionalInputStreamParams() = void_t();
|
||||
}
|
||||
else {
|
||||
nsString contentType;
|
||||
nsresult rv = aBlob->GetType(contentType);
|
||||
nsString contentType;
|
||||
nsresult rv = aBlob->GetType(contentType);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
uint64_t length;
|
||||
rv = aBlob->GetSize(&length);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
rv = aBlob->GetInternalStream(getter_AddRefs(stream));
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
InputStreamParams inputStreamParams;
|
||||
nsTArray<mozilla::ipc::FileDescriptor> fds;
|
||||
SerializeInputStream(stream, inputStreamParams, fds);
|
||||
|
||||
MOZ_ASSERT(fds.IsEmpty());
|
||||
|
||||
params.optionalInputStreamParams() = inputStreamParams;
|
||||
|
||||
nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
|
||||
if (file) {
|
||||
FileBlobConstructorParams fileParams;
|
||||
|
||||
rv = file->GetName(fileParams.name());
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
uint64_t length;
|
||||
rv = aBlob->GetSize(&length);
|
||||
rv = file->GetMozLastModifiedDate(&fileParams.modDate());
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
rv = aBlob->GetInternalStream(getter_AddRefs(stream));
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
fileParams.contentType() = contentType;
|
||||
fileParams.length() = length;
|
||||
|
||||
InputStreamParams inputStreamParams;
|
||||
nsTArray<mozilla::ipc::FileDescriptor> fds;
|
||||
SerializeInputStream(stream, inputStreamParams, fds);
|
||||
MOZ_ASSERT(fds.IsEmpty());
|
||||
|
||||
params.optionalInputStreamParams() = inputStreamParams;
|
||||
|
||||
nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
|
||||
if (file) {
|
||||
FileBlobConstructorParams fileParams;
|
||||
|
||||
rv = file->GetName(fileParams.name());
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
rv = file->GetMozLastModifiedDate(&fileParams.modDate());
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
fileParams.contentType() = contentType;
|
||||
fileParams.length() = length;
|
||||
|
||||
params.blobParams() = fileParams;
|
||||
} else {
|
||||
NormalBlobConstructorParams blobParams;
|
||||
blobParams.contentType() = contentType;
|
||||
blobParams.length() = length;
|
||||
params.blobParams() = blobParams;
|
||||
}
|
||||
params.blobParams() = fileParams;
|
||||
} else {
|
||||
NormalBlobConstructorParams blobParams;
|
||||
blobParams.contentType() = contentType;
|
||||
blobParams.length() = length;
|
||||
params.blobParams() = blobParams;
|
||||
}
|
||||
|
||||
BlobChild* actor = BlobChild::Create(this, aBlob);
|
||||
|
|
|
@ -2374,46 +2374,6 @@ ContentParent::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
|
|||
}
|
||||
}
|
||||
|
||||
// XXX This is only safe so long as all blob implementations in our tree
|
||||
// inherit nsDOMFileBase. If that ever changes then this will need to grow
|
||||
// a real interface or something.
|
||||
const nsDOMFileBase* blob = static_cast<nsDOMFileBase*>(aBlob);
|
||||
|
||||
// We often pass blobs that are multipart but that only contain one sub-blob
|
||||
// (WebActivities does this a bunch). Unwrap to reduce the number of actors
|
||||
// that we have to maintain.
|
||||
const nsTArray<nsCOMPtr<nsIDOMBlob> >* subBlobs = blob->GetSubBlobs();
|
||||
if (subBlobs && subBlobs->Length() == 1) {
|
||||
const nsCOMPtr<nsIDOMBlob>& subBlob = subBlobs->ElementAt(0);
|
||||
MOZ_ASSERT(subBlob);
|
||||
|
||||
// We can only take this shortcut if the multipart and the sub-blob are both
|
||||
// Blob objects or both File objects.
|
||||
nsCOMPtr<nsIDOMFile> multipartBlobAsFile = do_QueryInterface(aBlob);
|
||||
nsCOMPtr<nsIDOMFile> subBlobAsFile = do_QueryInterface(subBlob);
|
||||
if (!multipartBlobAsFile == !subBlobAsFile) {
|
||||
// The wrapping might have been unnecessary, see if we can simply pass an
|
||||
// existing remote blob for this ContentParent.
|
||||
if (nsCOMPtr<nsIRemoteBlob> remoteSubBlob = do_QueryInterface(subBlob)) {
|
||||
BlobParent* actor =
|
||||
static_cast<BlobParent*>(
|
||||
static_cast<PBlobParent*>(remoteSubBlob->GetPBlob()));
|
||||
MOZ_ASSERT(actor);
|
||||
|
||||
if (static_cast<ContentParent*>(actor->Manager()) == this) {
|
||||
return actor;
|
||||
}
|
||||
}
|
||||
|
||||
// No need to add a reference here since the original blob must have a
|
||||
// strong reference in the caller and it must also have a strong reference
|
||||
// to this sub-blob.
|
||||
aBlob = subBlob;
|
||||
blob = static_cast<nsDOMFileBase*>(aBlob);
|
||||
subBlobs = blob->GetSubBlobs();
|
||||
}
|
||||
}
|
||||
|
||||
// All blobs shared between processes must be immutable.
|
||||
nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(aBlob);
|
||||
if (!mutableBlob || NS_FAILED(mutableBlob->SetMutable(false))) {
|
||||
|
@ -2421,6 +2381,11 @@ ContentParent::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// XXX This is only safe so long as all blob implementations in our tree
|
||||
// inherit nsDOMFileBase. If that ever changes then this will need to grow
|
||||
// a real interface or something.
|
||||
const auto* blob = static_cast<nsDOMFileBase*>(aBlob);
|
||||
|
||||
ChildBlobConstructorParams params;
|
||||
|
||||
if (blob->IsSizeUnknown() || blob->IsDateUnknown()) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче