Bug 819900 - File constructor. r=sicking

This commit is contained in:
Andrea Marchesini 2013-10-31 11:27:12 -04:00
parent e1935ec872
commit 2c924a4923
4 changed files with 236 additions and 64 deletions

View File

@ -176,7 +176,22 @@ nsDOMMultipartFile::Initialize(nsISupports* aOwner,
if (!mIsFile) {
return InitBlob(aCx, aArgs.length(), aArgs.array(), GetXPConnectNative);
}
return InitFile(aCx, aArgs.length(), aArgs.array());
if (!nsContentUtils::IsCallerChrome()) {
return InitFile(aCx, aArgs.length(), aArgs.array());
}
if (aArgs.length() > 0) {
JS::Value* argv = aArgs.array();
if (argv[0].isObject()) {
JS::Rooted<JSObject*> obj(aCx, &argv[0].toObject());
if (JS_IsArrayObject(aCx, obj)) {
return InitFile(aCx, aArgs.length(), aArgs.array());
}
}
}
return InitChromeFile(aCx, aArgs.length(), aArgs.array());
}
nsresult
@ -196,66 +211,72 @@ nsDOMMultipartFile::InitBlob(JSContext* aCx,
}
if (aArgc > 0) {
if (!aArgv[0].isObject()) {
return NS_ERROR_TYPE_ERR; // We're not interested
}
JS::Rooted<JSObject*> obj(aCx, &aArgv[0].toObject());
if (!JS_IsArrayObject(aCx, obj)) {
return NS_ERROR_TYPE_ERR; // We're not interested
}
BlobSet blobSet;
uint32_t length;
JS_ALWAYS_TRUE(JS_GetArrayLength(aCx, obj, &length));
for (uint32_t i = 0; i < length; ++i) {
JS::Rooted<JS::Value> element(aCx);
if (!JS_GetElement(aCx, obj, i, &element))
return NS_ERROR_TYPE_ERR;
if (element.isObject()) {
JS::Rooted<JSObject*> obj(aCx, &element.toObject());
nsCOMPtr<nsIDOMBlob> blob = aUnwrapFunc(aCx, obj);
if (blob) {
// Flatten so that multipart blobs will never nest
nsDOMFileBase* file = static_cast<nsDOMFileBase*>(
static_cast<nsIDOMBlob*>(blob));
const nsTArray<nsCOMPtr<nsIDOMBlob> >*
subBlobs = file->GetSubBlobs();
if (subBlobs) {
blobSet.AppendBlobs(*subBlobs);
} else {
blobSet.AppendBlob(blob);
}
continue;
}
if (JS_IsArrayBufferViewObject(obj)) {
blobSet.AppendVoidPtr(JS_GetArrayBufferViewData(obj),
JS_GetArrayBufferViewByteLength(obj));
continue;
}
if (JS_IsArrayBufferObject(obj)) {
blobSet.AppendArrayBuffer(obj);
continue;
}
// neither Blob nor ArrayBuffer(View)
} else if (element.isString()) {
blobSet.AppendString(element.toString(), nativeEOL, aCx);
continue;
}
// coerce it to a string
JSString* str = JS_ValueToString(aCx, element);
NS_ENSURE_TRUE(str, NS_ERROR_TYPE_ERR);
blobSet.AppendString(str, nativeEOL, aCx);
}
mBlobs = blobSet.GetBlobs();
return ParseBlobArrayArgument(aCx, aArgv[0], nativeEOL, aUnwrapFunc);
}
return NS_OK;
}
nsresult
nsDOMMultipartFile::ParseBlobArrayArgument(JSContext* aCx, JS::Value& aValue,
bool aNativeEOL,
UnwrapFuncPtr aUnwrapFunc)
{
if (!aValue.isObject()) {
return NS_ERROR_TYPE_ERR; // We're not interested
}
JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
if (!JS_IsArrayObject(aCx, obj)) {
return NS_ERROR_TYPE_ERR; // We're not interested
}
BlobSet blobSet;
uint32_t length;
JS_ALWAYS_TRUE(JS_GetArrayLength(aCx, obj, &length));
for (uint32_t i = 0; i < length; ++i) {
JS::Rooted<JS::Value> element(aCx);
if (!JS_GetElement(aCx, obj, i, &element))
return NS_ERROR_TYPE_ERR;
if (element.isObject()) {
JS::Rooted<JSObject*> obj(aCx, &element.toObject());
nsCOMPtr<nsIDOMBlob> blob = aUnwrapFunc(aCx, obj);
if (blob) {
// Flatten so that multipart blobs will never nest
nsDOMFileBase* file = static_cast<nsDOMFileBase*>(
static_cast<nsIDOMBlob*>(blob));
const nsTArray<nsCOMPtr<nsIDOMBlob> >*
subBlobs = file->GetSubBlobs();
if (subBlobs) {
blobSet.AppendBlobs(*subBlobs);
} else {
blobSet.AppendBlob(blob);
}
continue;
}
if (JS_IsArrayBufferViewObject(obj)) {
blobSet.AppendVoidPtr(JS_GetArrayBufferViewData(obj),
JS_GetArrayBufferViewByteLength(obj));
continue;
}
if (JS_IsArrayBufferObject(obj)) {
blobSet.AppendArrayBuffer(obj);
continue;
}
}
// coerce it to a string
JSString* str = JS_ValueToString(aCx, element);
NS_ENSURE_TRUE(str, NS_ERROR_TYPE_ERR);
blobSet.AppendString(str, aNativeEOL, aCx);
}
mBlobs = blobSet.GetBlobs();
return NS_OK;
}
NS_IMETHODIMP
nsDOMMultipartFile::GetMozFullPathInternal(nsAString &aFilename)
{
@ -273,19 +294,15 @@ nsDOMMultipartFile::GetMozFullPathInternal(nsAString &aFilename)
}
nsresult
nsDOMMultipartFile::InitFile(JSContext* aCx,
uint32_t aArgc,
JS::Value* aArgv)
nsDOMMultipartFile::InitChromeFile(JSContext* aCx,
uint32_t aArgc,
JS::Value* aArgv)
{
nsresult rv;
NS_ASSERTION(!mImmutable, "Something went wrong ...");
NS_ENSURE_TRUE(!mImmutable, NS_ERROR_UNEXPECTED);
if (!nsContentUtils::IsCallerChrome()) {
return NS_ERROR_DOM_SECURITY_ERR; // Real short trip
}
MOZ_ASSERT(nsContentUtils::IsCallerChrome());
NS_ENSURE_TRUE(aArgc > 0, NS_ERROR_UNEXPECTED);
if (aArgc > 1) {
@ -367,6 +384,43 @@ nsDOMMultipartFile::InitFile(JSContext* aCx,
return NS_OK;
}
nsresult
nsDOMMultipartFile::InitFile(JSContext* aCx,
uint32_t aArgc,
JS::Value* aArgv)
{
NS_ASSERTION(!mImmutable, "Something went wrong ...");
NS_ENSURE_TRUE(!mImmutable, NS_ERROR_UNEXPECTED);
if (aArgc < 2) {
return NS_ERROR_TYPE_ERR;
}
// File name
JSString* str = JS_ValueToString(aCx, aArgv[1]);
NS_ENSURE_TRUE(str, NS_ERROR_XPC_BAD_CONVERT_JS);
nsDependentJSString xpcomStr;
if (!xpcomStr.init(aCx, str)) {
return NS_ERROR_XPC_BAD_CONVERT_JS;
}
mName = xpcomStr;
// Optional params
bool nativeEOL = false;
if (aArgc > 2) {
BlobPropertyBag d;
if (!d.Init(aCx, JS::Handle<JS::Value>::fromMarkedLocation(&aArgv[2]))) {
return NS_ERROR_TYPE_ERR;
}
mContentType = d.mType;
nativeEOL = d.mEndings == EndingTypes::Native;
}
return ParseBlobArrayArgument(aCx, aArgv[0], nativeEOL, GetXPConnectNative);
}
nsresult
BlobSet::AppendVoidPtr(const void* aData, uint32_t aLength)
{

View File

@ -73,6 +73,9 @@ public:
nsresult InitFile(JSContext* aCx,
uint32_t aArgc,
JS::Value* aArgv);
nsresult InitChromeFile(JSContext* aCx,
uint32_t aArgc,
JS::Value* aArgv);
already_AddRefed<nsIDOMBlob>
CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType) MOZ_OVERRIDE;
@ -103,6 +106,9 @@ public:
NS_IMETHOD GetMozFullPathInternal(nsAString& aFullPath) MOZ_OVERRIDE;
protected:
nsresult ParseBlobArrayArgument(JSContext* aCx, JS::Value& aValue,
bool aNativeEOL, UnwrapFuncPtr aUnwrapFunc);
nsTArray<nsCOMPtr<nsIDOMBlob> > mBlobs;
bool mIsFromNsiFile;
};

View File

@ -576,3 +576,4 @@ support-files =
[test_xhr_progressevents.html]
[test_xhr_send_readystate.html]
[test_xhr_withCredentials.html]
[test_file_from_blob.html]

View File

@ -0,0 +1,111 @@
<!doctype html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=819900
-->
<head>
<title>Test for crash caused by unloading and reloading srcdoc iframes</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=819900">Mozilla Bug 819900</a>
<pre id="test">
<script>
var b = new Blob(['1234567890']);
ok(b, 'Blob created');
is(b.size, 10, 'Blob has the right size');
var status = false;
try {
f = new File(b);
} catch(e) {
status = true;
}
ok(status, "File throws if the second argument is missing");
status = false;
try {
f = new File(42, 'foobar.txt');
} catch(e) {
status = true;
}
ok(status, "File throws if the argument is not an array");
status = false;
try {
f = new File({}, 'foobar.txt');
} catch(e) {
status = true;
}
ok(status, "File throws if the argument is not an array");
status = false;
try {
f = new File("hello world", 'foobar.txt');
} catch(e) {
status = true;
}
ok(status, "File throws if the argument is not an array");
f = new File(['1234567890'], '');
ok(f, 'File created');
is(f.size, 10, 'File has the right size');
is(f.name, '');
is(f.type, '');
f = new File(['1234567890'], 42);
ok(f, 'File created');
is(f.size, 10, 'File has the right size');
is(f.name, '42');
is(f.type, '');
f = new File(['1234567890'], 'text.txt');
ok(f, 'File created');
is(f.size, 10, 'File has the right size');
is(f.name, 'text.txt');
is(f.type, '');
f = new File(['1234567890'], 'text.txt', { type: 'plain/text' });
ok(f, 'File created');
is(f.size, 10, 'File has the right size');
is(f.name, 'text.txt');
is(f.type, 'plain/text');
f = new File([b], 'text.txt');
ok(f, 'File created');
is(f.name, 'text.txt');
is(f.type, '');
is(f.size, b.size);
f = new File([b], 'test.txt', { type: 'plain/text' });
ok(f, 'File created');
is(f.name, 'test.txt');
is(f.type, 'plain/text');
is(f.size, b.size);
f = new File([b, b], 'test.txt', { type: 'plain/text' });
ok(f, 'File created');
is(f.name, 'test.txt');
is(f.type, 'plain/text');
is(f.size, b.size * 2);
var f2 = new File([f, f], 'test.txt', { type: 'plain/text' });
ok(f2, 'File created');
is(f2.name, 'test.txt');
is(f2.type, 'plain/text');
is(f2.size, f.size * 2);
var f2 = new File([f, f], 'test.txt', b);
ok(f2, 'File created');
is(f2.name, 'test.txt');
is(f2.type, b.type);
is(f2.size, f.size * 2);
</script>
</pre>
</body>
</html>