Bug 982779 - Ensure that child->parent IPC blobs are never mysterious, r=baku.

This commit is contained in:
Ben Turner 2014-04-29 13:02:41 -07:00
Родитель 727cf86888
Коммит e7d0d6522b
7 изменённых файлов: 124 добавлений и 146 удалений

Просмотреть файл

@ -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()) {