зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1127703 - Support iteration on FormData, r=bz
This commit is contained in:
Родитель
cc10dd7ad3
Коммит
c628603a97
|
@ -862,16 +862,16 @@ WriteFormData(JSStructuredCloneWriter* aWriter,
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
Write(const nsString& aName, bool isFile, const nsString& aValue,
|
Write(const nsString& aName, const OwningFileOrUSVString& aValue,
|
||||||
File* aFile, void* aClosure)
|
void* aClosure)
|
||||||
{
|
{
|
||||||
Closure* closure = static_cast<Closure*>(aClosure);
|
Closure* closure = static_cast<Closure*>(aClosure);
|
||||||
if (!WriteString(closure->mWriter, aName)) {
|
if (!WriteString(closure->mWriter, aName)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isFile) {
|
if (aValue.IsFile()) {
|
||||||
BlobImpl* blobImpl = aFile->Impl();
|
BlobImpl* blobImpl = aValue.GetAsFile()->Impl();
|
||||||
if (!JS_WriteUint32Pair(closure->mWriter, SCTAG_DOM_BLOB,
|
if (!JS_WriteUint32Pair(closure->mWriter, SCTAG_DOM_BLOB,
|
||||||
closure->mHolder->BlobImpls().Length())) {
|
closure->mHolder->BlobImpls().Length())) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -882,9 +882,10 @@ WriteFormData(JSStructuredCloneWriter* aWriter,
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t charSize = sizeof(nsString::char_type);
|
size_t charSize = sizeof(nsString::char_type);
|
||||||
if (!JS_WriteUint32Pair(closure->mWriter, 0, aValue.Length()) ||
|
if (!JS_WriteUint32Pair(closure->mWriter, 0,
|
||||||
!JS_WriteBytes(closure->mWriter, aValue.get(),
|
aValue.GetAsUSVString().Length()) ||
|
||||||
aValue.Length() * charSize)) {
|
!JS_WriteBytes(closure->mWriter, aValue.GetAsUSVString().get(),
|
||||||
|
aValue.GetAsUSVString().Length() * charSize)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,9 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsFormData)
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
|
||||||
|
|
||||||
for (uint32_t i = 0, len = tmp->mFormData.Length(); i < len; ++i) {
|
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
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||||
|
@ -71,8 +73,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsFormData)
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
|
||||||
|
|
||||||
for (uint32_t i = 0, len = tmp->mFormData.Length(); i < len; ++i) {
|
for (uint32_t i = 0, len = tmp->mFormData.Length(); i < len; ++i) {
|
||||||
ImplCycleCollectionTraverse(cb,tmp->mFormData[i].fileValue,
|
ImplCycleCollectionTraverse(cb, tmp->mFormData[i].value,
|
||||||
"mFormData[i].fileValue", 0);
|
"mFormData[i].GetAsFile()", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
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
|
void
|
||||||
nsFormData::Get(const nsAString& aName,
|
nsFormData::Get(const nsAString& aName,
|
||||||
Nullable<OwningFileOrUSVString>& aOutValue)
|
Nullable<OwningFileOrUSVString>& aOutValue)
|
||||||
{
|
{
|
||||||
for (uint32_t i = 0; i < mFormData.Length(); ++i) {
|
for (uint32_t i = 0; i < mFormData.Length(); ++i) {
|
||||||
if (aName.Equals(mFormData[i].name)) {
|
if (aName.Equals(mFormData[i].name)) {
|
||||||
ExtractValue(mFormData[i], &aOutValue.SetValue());
|
aOutValue.SetValue() = mFormData[i].value;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,7 +149,7 @@ nsFormData::GetAll(const nsAString& aName,
|
||||||
for (uint32_t i = 0; i < mFormData.Length(); ++i) {
|
for (uint32_t i = 0; i < mFormData.Length(); ++i) {
|
||||||
if (aName.Equals(mFormData[i].name)) {
|
if (aName.Equals(mFormData[i].name)) {
|
||||||
OwningFileOrUSVString* element = aValues.AppendElement();
|
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
|
// nsIDOMFormData
|
||||||
|
|
||||||
|
@ -297,11 +308,11 @@ nsFormData::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength,
|
||||||
nsFSMultipartFormData fs(NS_LITERAL_CSTRING("UTF-8"), nullptr);
|
nsFSMultipartFormData fs(NS_LITERAL_CSTRING("UTF-8"), nullptr);
|
||||||
|
|
||||||
for (uint32_t i = 0; i < mFormData.Length(); ++i) {
|
for (uint32_t i = 0; i < mFormData.Length(); ++i) {
|
||||||
if (mFormData[i].valueIsFile) {
|
if (mFormData[i].value.IsFile()) {
|
||||||
fs.AddNameFilePair(mFormData[i].name, mFormData[i].fileValue);
|
fs.AddNameFilePair(mFormData[i].name, mFormData[i].value.GetAsFile());
|
||||||
}
|
} else {
|
||||||
else {
|
fs.AddNameValuePair(mFormData[i].name,
|
||||||
fs.AddNameValuePair(mFormData[i].name, mFormData[i].stringValue);
|
mFormData[i].value.GetAsUSVString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,13 +37,12 @@ private:
|
||||||
|
|
||||||
typedef mozilla::dom::Blob Blob;
|
typedef mozilla::dom::Blob Blob;
|
||||||
typedef mozilla::dom::File File;
|
typedef mozilla::dom::File File;
|
||||||
|
typedef mozilla::dom::OwningFileOrUSVString OwningFileOrUSVString;
|
||||||
|
|
||||||
struct FormDataTuple
|
struct FormDataTuple
|
||||||
{
|
{
|
||||||
nsString name;
|
nsString name;
|
||||||
nsString stringValue;
|
OwningFileOrUSVString value;
|
||||||
RefPtr<File> fileValue;
|
|
||||||
bool valueIsFile;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns the FormDataTuple to modify. This may be null, in which case
|
// Returns the FormDataTuple to modify. This may be null, in which case
|
||||||
|
@ -57,8 +56,7 @@ private:
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aData);
|
MOZ_ASSERT(aData);
|
||||||
aData->name = aName;
|
aData->name = aName;
|
||||||
aData->stringValue = aValue;
|
aData->value.SetAsUSVString() = aValue;
|
||||||
aData->valueIsFile = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetNameFilePair(FormDataTuple* aData,
|
void SetNameFilePair(FormDataTuple* aData,
|
||||||
|
@ -67,12 +65,9 @@ private:
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aData);
|
MOZ_ASSERT(aData);
|
||||||
aData->name = aName;
|
aData->name = aName;
|
||||||
aData->fileValue = aFile;
|
aData->value.SetAsFile() = aFile;
|
||||||
aData->valueIsFile = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExtractValue(const FormDataTuple& aTuple,
|
|
||||||
mozilla::dom::OwningFileOrUSVString* aOutValue);
|
|
||||||
public:
|
public:
|
||||||
explicit nsFormData(nsISupports* aOwner = nullptr);
|
explicit nsFormData(nsISupports* aOwner = nullptr);
|
||||||
|
|
||||||
|
@ -100,13 +95,17 @@ public:
|
||||||
void Append(const nsAString& aName, Blob& aBlob,
|
void Append(const nsAString& aName, Blob& aBlob,
|
||||||
const mozilla::dom::Optional<nsAString>& aFilename);
|
const mozilla::dom::Optional<nsAString>& aFilename);
|
||||||
void Delete(const nsAString& aName);
|
void Delete(const nsAString& aName);
|
||||||
void Get(const nsAString& aName, mozilla::dom::Nullable<mozilla::dom::OwningFileOrUSVString>& aOutValue);
|
void Get(const nsAString& aName, mozilla::dom::Nullable<OwningFileOrUSVString>& aOutValue);
|
||||||
void GetAll(const nsAString& aName, nsTArray<mozilla::dom::OwningFileOrUSVString>& aValues);
|
void GetAll(const nsAString& aName, nsTArray<OwningFileOrUSVString>& aValues);
|
||||||
bool Has(const nsAString& aName);
|
bool Has(const nsAString& aName);
|
||||||
void Set(const nsAString& aName, Blob& aBlob,
|
void Set(const nsAString& aName, Blob& aBlob,
|
||||||
const mozilla::dom::Optional<nsAString>& aFilename);
|
const mozilla::dom::Optional<nsAString>& aFilename);
|
||||||
void Set(const nsAString& aName, const nsAString& aValue);
|
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
|
// nsFormSubmission
|
||||||
virtual nsresult GetEncodedSubmission(nsIURI* aURI,
|
virtual nsresult GetEncodedSubmission(nsIURI* aURI,
|
||||||
nsIInputStream** aPostDataStream) override;
|
nsIInputStream** aPostDataStream) override;
|
||||||
|
@ -120,9 +119,9 @@ public:
|
||||||
virtual nsresult AddNameFilePair(const nsAString& aName,
|
virtual nsresult AddNameFilePair(const nsAString& aName,
|
||||||
File* aFile) override;
|
File* aFile) override;
|
||||||
|
|
||||||
typedef bool (*FormDataEntryCallback)(const nsString& aName, bool aIsFile,
|
typedef bool (*FormDataEntryCallback)(const nsString& aName,
|
||||||
const nsString& aValue,
|
const OwningFileOrUSVString& aValue,
|
||||||
File* aFile, void* aClosure);
|
void* aClosure);
|
||||||
|
|
||||||
uint32_t
|
uint32_t
|
||||||
Length() const
|
Length() const
|
||||||
|
@ -137,8 +136,7 @@ public:
|
||||||
{
|
{
|
||||||
for (uint32_t i = 0; i < mFormData.Length(); ++i) {
|
for (uint32_t i = 0; i < mFormData.Length(); ++i) {
|
||||||
FormDataTuple& tuple = mFormData[i];
|
FormDataTuple& tuple = mFormData[i];
|
||||||
if (!aFunc(tuple.name, tuple.valueIsFile, tuple.stringValue,
|
if (!aFunc(tuple.name, tuple.value, aClosure)) {
|
||||||
tuple.fileValue, aClosure)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,6 +105,56 @@ function testFilename() {
|
||||||
is(f.get("file3").name, "", "File's filename is returned even if empty.");
|
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) {
|
function testSend(doneCb) {
|
||||||
var xhr = new XMLHttpRequest();
|
var xhr = new XMLHttpRequest();
|
||||||
xhr.open("POST", "form_submit_server.sjs");
|
xhr.open("POST", "form_submit_server.sjs");
|
||||||
|
@ -161,6 +211,7 @@ function runTest(doneCb) {
|
||||||
testSet();
|
testSet();
|
||||||
testIterate();
|
testIterate();
|
||||||
testFilename();
|
testFilename();
|
||||||
|
testIterable();
|
||||||
// Finally, send an XHR and verify the response matches.
|
// Finally, send an XHR and verify the response matches.
|
||||||
testSend(doneCb);
|
testSend(doneCb);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,5 +20,5 @@ interface FormData {
|
||||||
boolean has(USVString name);
|
boolean has(USVString name);
|
||||||
void set(USVString name, Blob value, optional USVString filename);
|
void set(USVString name, Blob value, optional USVString filename);
|
||||||
void set(USVString name, USVString value);
|
void set(USVString name, USVString value);
|
||||||
// iterable<USVString, FormDataEntryValue>; - Bug 1127703
|
iterable<USVString, FormDataEntryValue>;
|
||||||
};
|
};
|
||||||
|
|
Загрузка…
Ссылка в новой задаче