зеркало из 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 "nsWrapperCache.h"
|
||||||
#include "nsCycleCollectionParticipant.h"
|
#include "nsCycleCollectionParticipant.h"
|
||||||
|
|
||||||
|
class nsDOMMultipartFile;
|
||||||
class nsIFile;
|
class nsIFile;
|
||||||
class nsIInputStream;
|
class nsIInputStream;
|
||||||
class nsIClassInfo;
|
class nsIClassInfo;
|
||||||
|
@ -42,6 +43,8 @@ class nsDOMFileBase : public nsIDOMFile,
|
||||||
public nsIXHRSendable,
|
public nsIXHRSendable,
|
||||||
public nsIMutable
|
public nsIMutable
|
||||||
{
|
{
|
||||||
|
friend class nsDOMMultipartFile;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef mozilla::dom::indexedDB::FileInfo FileInfo;
|
typedef mozilla::dom::indexedDB::FileInfo FileInfo;
|
||||||
|
|
||||||
|
@ -361,8 +364,9 @@ public:
|
||||||
nsDOMMemoryFile(void *aMemoryBuffer,
|
nsDOMMemoryFile(void *aMemoryBuffer,
|
||||||
uint64_t aLength,
|
uint64_t aLength,
|
||||||
const nsAString& aName,
|
const nsAString& aName,
|
||||||
const nsAString& aContentType)
|
const nsAString& aContentType,
|
||||||
: nsDOMFile(aName, aContentType, aLength, UINT64_MAX),
|
uint64_t aLastModifiedDate)
|
||||||
|
: nsDOMFile(aName, aContentType, aLength, aLastModifiedDate),
|
||||||
mDataOwner(new DataOwner(aMemoryBuffer, aLength))
|
mDataOwner(new DataOwner(aMemoryBuffer, aLength))
|
||||||
{
|
{
|
||||||
NS_ASSERTION(mDataOwner && mDataOwner->mData, "must have data");
|
NS_ASSERTION(mDataOwner && mDataOwner->mData, "must have data");
|
||||||
|
|
|
@ -27,26 +27,6 @@ NS_IMPL_ISUPPORTS_INHERITED(nsDOMMultipartFile, nsDOMFile,
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsDOMMultipartFile::GetSize(uint64_t* aLength)
|
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;
|
*aLength = mLength;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -214,6 +194,8 @@ nsDOMMultipartFile::InitBlob(JSContext* aCx,
|
||||||
return ParseBlobArrayArgument(aCx, aArgv[0], nativeEOL, aUnwrapFunc);
|
return ParseBlobArrayArgument(aCx, aArgv[0], nativeEOL, aUnwrapFunc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetLengthAndModifiedDate();
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,9 +261,48 @@ nsDOMMultipartFile::ParseBlobArrayArgument(JSContext* aCx, JS::Value& aValue,
|
||||||
}
|
}
|
||||||
|
|
||||||
mBlobs = blobSet.GetBlobs();
|
mBlobs = blobSet.GetBlobs();
|
||||||
|
|
||||||
|
SetLengthAndModifiedDate();
|
||||||
|
|
||||||
return NS_OK;
|
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
|
NS_IMETHODIMP
|
||||||
nsDOMMultipartFile::GetMozFullPathInternal(nsAString &aFilename)
|
nsDOMMultipartFile::GetMozFullPathInternal(nsAString &aFilename)
|
||||||
{
|
{
|
||||||
|
@ -374,7 +395,18 @@ nsDOMMultipartFile::InitChromeFile(JSContext* aCx,
|
||||||
file->GetLeafName(mName);
|
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
|
// XXXkhuey this is terrible
|
||||||
|
@ -386,6 +418,8 @@ nsDOMMultipartFile::InitChromeFile(JSContext* aCx,
|
||||||
blobSet.AppendBlob(blob);
|
blobSet.AppendBlob(blob);
|
||||||
mBlobs = blobSet.GetBlobs();
|
mBlobs = blobSet.GetBlobs();
|
||||||
|
|
||||||
|
SetLengthAndModifiedDate();
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ public:
|
||||||
mBlobs(aBlobs),
|
mBlobs(aBlobs),
|
||||||
mIsFromNsiFile(false)
|
mIsFromNsiFile(false)
|
||||||
{
|
{
|
||||||
|
SetLengthAndModifiedDate();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create as a blob
|
// Create as a blob
|
||||||
|
@ -41,6 +42,7 @@ public:
|
||||||
mBlobs(aBlobs),
|
mBlobs(aBlobs),
|
||||||
mIsFromNsiFile(false)
|
mIsFromNsiFile(false)
|
||||||
{
|
{
|
||||||
|
SetLengthAndModifiedDate();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create as a file to be later initialized
|
// Create as a file to be later initialized
|
||||||
|
@ -109,6 +111,8 @@ protected:
|
||||||
nsresult ParseBlobArrayArgument(JSContext* aCx, JS::Value& aValue,
|
nsresult ParseBlobArrayArgument(JSContext* aCx, JS::Value& aValue,
|
||||||
bool aNativeEOL, UnwrapFuncPtr aUnwrapFunc);
|
bool aNativeEOL, UnwrapFuncPtr aUnwrapFunc);
|
||||||
|
|
||||||
|
void SetLengthAndModifiedDate();
|
||||||
|
|
||||||
nsTArray<nsCOMPtr<nsIDOMBlob> > mBlobs;
|
nsTArray<nsCOMPtr<nsIDOMBlob> > mBlobs;
|
||||||
bool mIsFromNsiFile;
|
bool mIsFromNsiFile;
|
||||||
};
|
};
|
||||||
|
@ -170,7 +174,7 @@ protected:
|
||||||
// and put it on the stack
|
// and put it on the stack
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMBlob> blob =
|
nsCOMPtr<nsIDOMBlob> blob =
|
||||||
new nsDOMMemoryFile(mData, mDataLen, EmptyString(), EmptyString());
|
new nsDOMMemoryFile(mData, mDataLen, EmptyString());
|
||||||
mBlobs.AppendElement(blob);
|
mBlobs.AppendElement(blob);
|
||||||
mData = nullptr; // The nsDOMMemoryFile takes ownership of the buffer
|
mData = nullptr; // The nsDOMMemoryFile takes ownership of the buffer
|
||||||
mDataLen = 0;
|
mDataLen = 0;
|
||||||
|
|
|
@ -591,7 +591,7 @@ HTMLCanvasElement::MozGetAsFileImpl(const nsAString& aName,
|
||||||
|
|
||||||
// The DOMFile takes ownership of the buffer
|
// The DOMFile takes ownership of the buffer
|
||||||
nsRefPtr<nsDOMMemoryFile> file =
|
nsRefPtr<nsDOMMemoryFile> file =
|
||||||
new nsDOMMemoryFile(imgData, (uint32_t)imgSize, aName, type);
|
new nsDOMMemoryFile(imgData, (uint32_t)imgSize, aName, type, PR_Now());
|
||||||
|
|
||||||
file.forget(aResult);
|
file.forget(aResult);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
|
@ -1821,10 +1821,15 @@ BlobParent::Create(ContentParent* aManager,
|
||||||
|
|
||||||
const ChildBlobConstructorParams& blobParams = aParams.blobParams();
|
const ChildBlobConstructorParams& blobParams = aParams.blobParams();
|
||||||
|
|
||||||
|
MOZ_ASSERT(blobParams.type() !=
|
||||||
|
ChildBlobConstructorParams::TMysteryBlobConstructorParams);
|
||||||
|
|
||||||
switch (blobParams.type()) {
|
switch (blobParams.type()) {
|
||||||
|
case ChildBlobConstructorParams::TMysteryBlobConstructorParams:
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
case ChildBlobConstructorParams::TNormalBlobConstructorParams:
|
case ChildBlobConstructorParams::TNormalBlobConstructorParams:
|
||||||
case ChildBlobConstructorParams::TFileBlobConstructorParams:
|
case ChildBlobConstructorParams::TFileBlobConstructorParams:
|
||||||
case ChildBlobConstructorParams::TMysteryBlobConstructorParams:
|
|
||||||
return new BlobParent(aManager, aParams);
|
return new BlobParent(aManager, aParams);
|
||||||
|
|
||||||
case ChildBlobConstructorParams::TSlicedBlobConstructorParams: {
|
case ChildBlobConstructorParams::TSlicedBlobConstructorParams: {
|
||||||
|
|
|
@ -876,43 +876,6 @@ ContentChild::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
|
||||||
return actor;
|
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.
|
// All blobs shared between processes must be immutable.
|
||||||
nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(aBlob);
|
nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(aBlob);
|
||||||
if (!mutableBlob || NS_FAILED(mutableBlob->SetMutable(false))) {
|
if (!mutableBlob || NS_FAILED(mutableBlob->SetMutable(false))) {
|
||||||
|
@ -920,56 +883,59 @@ ContentChild::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
|
||||||
return nullptr;
|
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;
|
ParentBlobConstructorParams params;
|
||||||
|
|
||||||
if (blob->IsSizeUnknown() || blob->IsDateUnknown()) {
|
nsString contentType;
|
||||||
// We don't want to call GetSize or GetLastModifiedDate
|
nsresult rv = aBlob->GetType(contentType);
|
||||||
// yet since that may stat a file on the main thread
|
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||||
// here. Instead we'll learn the size lazily from the
|
|
||||||
// other process.
|
uint64_t length;
|
||||||
params.blobParams() = MysteryBlobConstructorParams();
|
rv = aBlob->GetSize(&length);
|
||||||
params.optionalInputStreamParams() = void_t();
|
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||||
}
|
|
||||||
else {
|
nsCOMPtr<nsIInputStream> stream;
|
||||||
nsString contentType;
|
rv = aBlob->GetInternalStream(getter_AddRefs(stream));
|
||||||
nsresult rv = aBlob->GetType(contentType);
|
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);
|
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||||
|
|
||||||
uint64_t length;
|
rv = file->GetMozLastModifiedDate(&fileParams.modDate());
|
||||||
rv = aBlob->GetSize(&length);
|
|
||||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||||
|
|
||||||
nsCOMPtr<nsIInputStream> stream;
|
fileParams.contentType() = contentType;
|
||||||
rv = aBlob->GetInternalStream(getter_AddRefs(stream));
|
fileParams.length() = length;
|
||||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
|
||||||
|
|
||||||
InputStreamParams inputStreamParams;
|
params.blobParams() = fileParams;
|
||||||
nsTArray<mozilla::ipc::FileDescriptor> fds;
|
} else {
|
||||||
SerializeInputStream(stream, inputStreamParams, fds);
|
NormalBlobConstructorParams blobParams;
|
||||||
MOZ_ASSERT(fds.IsEmpty());
|
blobParams.contentType() = contentType;
|
||||||
|
blobParams.length() = length;
|
||||||
params.optionalInputStreamParams() = inputStreamParams;
|
params.blobParams() = blobParams;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BlobChild* actor = BlobChild::Create(this, aBlob);
|
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.
|
// All blobs shared between processes must be immutable.
|
||||||
nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(aBlob);
|
nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(aBlob);
|
||||||
if (!mutableBlob || NS_FAILED(mutableBlob->SetMutable(false))) {
|
if (!mutableBlob || NS_FAILED(mutableBlob->SetMutable(false))) {
|
||||||
|
@ -2421,6 +2381,11 @@ ContentParent::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
|
||||||
return nullptr;
|
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;
|
ChildBlobConstructorParams params;
|
||||||
|
|
||||||
if (blob->IsSizeUnknown() || blob->IsDateUnknown()) {
|
if (blob->IsSizeUnknown() || blob->IsDateUnknown()) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче