From c94d30fc3402a450fe0c7b5be153c0d08e395bdb Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Mon, 19 Oct 2015 16:16:42 +0100 Subject: [PATCH] Bug 1127703 - Support iteration on FormData, r=bz --- dom/base/StructuredCloneHolder.cpp | 15 +++++---- dom/base/nsFormData.cpp | 53 ++++++++++++++++++------------ dom/base/nsFormData.h | 17 ++++++---- dom/html/test/formData_test.js | 51 ++++++++++++++++++++++++++++ dom/webidl/FormData.webidl | 2 +- 5 files changed, 102 insertions(+), 36 deletions(-) diff --git a/dom/base/StructuredCloneHolder.cpp b/dom/base/StructuredCloneHolder.cpp index 98d8f978dae5..6fc6229f2bb2 100644 --- a/dom/base/StructuredCloneHolder.cpp +++ b/dom/base/StructuredCloneHolder.cpp @@ -862,16 +862,16 @@ WriteFormData(JSStructuredCloneWriter* aWriter, { } static bool - Write(const nsString& aName, bool isFile, const nsString& aValue, - File* aFile, void* aClosure) + Write(const nsString& aName, const OwningFileOrUSVString& aValue, + void* aClosure) { Closure* closure = static_cast(aClosure); if (!WriteString(closure->mWriter, aName)) { return false; } - if (isFile) { - BlobImpl* blobImpl = aFile->Impl(); + if (aValue.IsFile()) { + BlobImpl* blobImpl = aValue.GetAsFile()->Impl(); if (!JS_WriteUint32Pair(closure->mWriter, SCTAG_DOM_BLOB, closure->mHolder->BlobImpls().Length())) { return false; @@ -882,9 +882,10 @@ WriteFormData(JSStructuredCloneWriter* aWriter, } size_t charSize = sizeof(nsString::char_type); - if (!JS_WriteUint32Pair(closure->mWriter, 0, aValue.Length()) || - !JS_WriteBytes(closure->mWriter, aValue.get(), - aValue.Length() * charSize)) { + if (!JS_WriteUint32Pair(closure->mWriter, 0, + aValue.GetAsUSVString().Length()) || + !JS_WriteBytes(closure->mWriter, aValue.GetAsUSVString().get(), + aValue.GetAsUSVString().Length() * charSize)) { return false; } diff --git a/dom/base/nsFormData.cpp b/dom/base/nsFormData.cpp index bc923629c493..f87a1eab37f7 100644 --- a/dom/base/nsFormData.cpp +++ b/dom/base/nsFormData.cpp @@ -61,7 +61,9 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsFormData) NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner) for (uint32_t i = 0, len = tmp->mFormData.Length(); i < len; ++i) { - ImplCycleCollectionUnlink(tmp->mFormData[i].fileValue); + if (tmp->mFormData[i].value.IsFile()) { + ImplCycleCollectionUnlink(tmp->mFormData[i].value); + } } NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER @@ -71,8 +73,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsFormData) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner) for (uint32_t i = 0, len = tmp->mFormData.Length(); i < len; ++i) { - ImplCycleCollectionTraverse(cb,tmp->mFormData[i].fileValue, - "mFormData[i].fileValue", 0); + ImplCycleCollectionTraverse(cb, tmp->mFormData[i].value, + "mFormData[i].GetAsFile()", 0); } NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS @@ -126,24 +128,13 @@ nsFormData::Delete(const nsAString& aName) } } -void -nsFormData::ExtractValue(const FormDataTuple& aTuple, - OwningFileOrUSVString* aOutValue) -{ - if (aTuple.valueIsFile) { - aOutValue->SetAsFile() = aTuple.fileValue; - } else { - aOutValue->SetAsUSVString() = aTuple.stringValue; - } -} - void nsFormData::Get(const nsAString& aName, Nullable& aOutValue) { for (uint32_t i = 0; i < mFormData.Length(); ++i) { if (aName.Equals(mFormData[i].name)) { - ExtractValue(mFormData[i], &aOutValue.SetValue()); + aOutValue.SetValue() = mFormData[i].value; return; } } @@ -158,7 +149,7 @@ nsFormData::GetAll(const nsAString& aName, for (uint32_t i = 0; i < mFormData.Length(); ++i) { if (aName.Equals(mFormData[i].name)) { OwningFileOrUSVString* element = aValues.AppendElement(); - ExtractValue(mFormData[i], element); + *element = mFormData[i].value; } } } @@ -229,6 +220,26 @@ nsFormData::Set(const nsAString& aName, const nsAString& aValue) } } +uint32_t +nsFormData::GetIterableLength() const +{ + return mFormData.Length(); +} + +const nsAString& +nsFormData::GetKeyAtIndex(uint32_t aIndex) const +{ + MOZ_ASSERT(aIndex < mFormData.Length()); + return mFormData[aIndex].name; +} + +const OwningFileOrUSVString& +nsFormData::GetValueAtIndex(uint32_t aIndex) const +{ + MOZ_ASSERT(aIndex < mFormData.Length()); + return mFormData[aIndex].value; +} + // ------------------------------------------------------------------------- // nsIDOMFormData @@ -297,11 +308,11 @@ nsFormData::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength, nsFSMultipartFormData fs(NS_LITERAL_CSTRING("UTF-8"), nullptr); for (uint32_t i = 0; i < mFormData.Length(); ++i) { - if (mFormData[i].valueIsFile) { - fs.AddNameFilePair(mFormData[i].name, mFormData[i].fileValue); - } - else { - fs.AddNameValuePair(mFormData[i].name, mFormData[i].stringValue); + if (mFormData[i].value.IsFile()) { + fs.AddNameFilePair(mFormData[i].name, mFormData[i].value.GetAsFile()); + } else { + fs.AddNameValuePair(mFormData[i].name, + mFormData[i].value.GetAsUSVString()); } } diff --git a/dom/base/nsFormData.h b/dom/base/nsFormData.h index 0ec96f5945b1..0dae4d3b72ad 100644 --- a/dom/base/nsFormData.h +++ b/dom/base/nsFormData.h @@ -100,13 +100,17 @@ public: void Append(const nsAString& aName, Blob& aBlob, const mozilla::dom::Optional& aFilename); void Delete(const nsAString& aName); - void Get(const nsAString& aName, mozilla::dom::Nullable& aOutValue); - void GetAll(const nsAString& aName, nsTArray& aValues); + void Get(const nsAString& aName, mozilla::dom::Nullable& aOutValue); + void GetAll(const nsAString& aName, nsTArray& aValues); bool Has(const nsAString& aName); void Set(const nsAString& aName, Blob& aBlob, const mozilla::dom::Optional& aFilename); void Set(const nsAString& aName, const nsAString& aValue); + uint32_t GetIterableLength() const; + const nsAString& GetKeyAtIndex(uint32_t aIndex) const; + const OwningFileOrUSVString& GetValueAtIndex(uint32_t aIndex) const; + // nsFormSubmission virtual nsresult GetEncodedSubmission(nsIURI* aURI, nsIInputStream** aPostDataStream) override; @@ -120,9 +124,9 @@ public: virtual nsresult AddNameFilePair(const nsAString& aName, File* aFile) override; - typedef bool (*FormDataEntryCallback)(const nsString& aName, bool aIsFile, - const nsString& aValue, - File* aFile, void* aClosure); + typedef bool (*FormDataEntryCallback)(const nsString& aName, + const OwningFileOrUSVString& aValue, + void* aClosure); uint32_t Length() const @@ -137,8 +141,7 @@ public: { for (uint32_t i = 0; i < mFormData.Length(); ++i) { FormDataTuple& tuple = mFormData[i]; - if (!aFunc(tuple.name, tuple.valueIsFile, tuple.stringValue, - tuple.fileValue, aClosure)) { + if (!aFunc(tuple.name, tuple.value, aClosure)) { return false; } } diff --git a/dom/html/test/formData_test.js b/dom/html/test/formData_test.js index 613dc98238bf..4194f123322f 100644 --- a/dom/html/test/formData_test.js +++ b/dom/html/test/formData_test.js @@ -105,6 +105,56 @@ function testFilename() { is(f.get("file3").name, "", "File's filename is returned even if empty."); } +function testIterable() { + var fd = new FormData(); + fd.set('1','2'); + fd.set('2','4'); + fd.set('3','6'); + fd.set('4','8'); + fd.set('5','10'); + + var key_iter = fd.keys(); + var value_iter = fd.values(); + var entries_iter = fd.entries(); + for (var i = 0; i < 5; ++i) { + var v = i + 1; + var key = key_iter.next(); + var value = value_iter.next(); + var entry = entries_iter.next(); + is(key.value, v.toString(), "Correct Key iterator: " + v.toString()); + ok(!key.done, "key.done is false"); + is(value.value, (v * 2).toString(), "Correct Value iterator: " + (v * 2).toString()); + ok(!value.done, "value.done is false"); + is(entry.value[0], v.toString(), "Correct Entry 0 iterator: " + v.toString()); + is(entry.value[1], (v * 2).toString(), "Correct Entry 1 iterator: " + (v * 2).toString()); + ok(!entry.done, "entry.done is false"); + } + + var last = key_iter.next(); + ok(last.done, "Nothing more to read."); + is(last.value, undefined, "Undefined is the last key"); + + last = value_iter.next(); + ok(last.done, "Nothing more to read."); + is(last.value, undefined, "Undefined is the last value"); + + last = entries_iter.next(); + ok(last.done, "Nothing more to read."); + + key_iter = fd.keys(); + key_iter.next(); + key_iter.next(); + fd.delete('1'); + fd.delete('2'); + fd.delete('3'); + fd.delete('4'); + fd.delete('5'); + + last = key_iter.next(); + ok(last.done, "Nothing more to read."); + is(last.value, undefined, "Undefined is the last key"); +} + function testSend(doneCb) { var xhr = new XMLHttpRequest(); xhr.open("POST", "form_submit_server.sjs"); @@ -161,6 +211,7 @@ function runTest(doneCb) { testSet(); testIterate(); testFilename(); + testIterable(); // Finally, send an XHR and verify the response matches. testSend(doneCb); } diff --git a/dom/webidl/FormData.webidl b/dom/webidl/FormData.webidl index fd8bb539e23c..f5902c4efe00 100644 --- a/dom/webidl/FormData.webidl +++ b/dom/webidl/FormData.webidl @@ -20,5 +20,5 @@ interface FormData { boolean has(USVString name); void set(USVString name, Blob value, optional USVString filename); void set(USVString name, USVString value); - // iterable; - Bug 1127703 + iterable; };