mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1085283 - Patch 1 Implement FormData manipulation methods. r=baku
This commit is contained in:
parent
864ffaf330
commit
a9d8abf718
@ -6,9 +6,7 @@
|
||||
#include "nsIVariant.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/HTMLFormElement.h"
|
||||
#include "mozilla/dom/FormDataBinding.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
@ -86,6 +84,119 @@ nsFormData::Append(const nsAString& aName, File& aBlob,
|
||||
AddNameFilePair(aName, &aBlob, filename);
|
||||
}
|
||||
|
||||
void
|
||||
nsFormData::Delete(const nsAString& aName)
|
||||
{
|
||||
// We have to use this slightly awkward for loop since uint32_t >= 0 is an
|
||||
// error for being always true.
|
||||
for (uint32_t i = mFormData.Length(); i-- > 0; ) {
|
||||
if (aName.Equals(mFormData[i].name)) {
|
||||
mFormData.RemoveElementAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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<OwningFileOrUSVString>& aOutValue)
|
||||
{
|
||||
for (uint32_t i = 0; i < mFormData.Length(); ++i) {
|
||||
if (aName.Equals(mFormData[i].name)) {
|
||||
ExtractValue(mFormData[i], &aOutValue.SetValue());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
aOutValue.SetNull();
|
||||
}
|
||||
|
||||
void
|
||||
nsFormData::GetAll(const nsAString& aName,
|
||||
nsTArray<OwningFileOrUSVString>& aValues)
|
||||
{
|
||||
for (uint32_t i = 0; i < mFormData.Length(); ++i) {
|
||||
if (aName.Equals(mFormData[i].name)) {
|
||||
OwningFileOrUSVString* element = aValues.AppendElement();
|
||||
ExtractValue(mFormData[i], element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsFormData::Has(const nsAString& aName)
|
||||
{
|
||||
for (uint32_t i = 0; i < mFormData.Length(); ++i) {
|
||||
if (aName.Equals(mFormData[i].name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
nsFormData::FormDataTuple*
|
||||
nsFormData::RemoveAllOthersAndGetFirstFormDataTuple(const nsAString& aName)
|
||||
{
|
||||
FormDataTuple* lastFoundTuple = nullptr;
|
||||
uint32_t lastFoundIndex = mFormData.Length();
|
||||
// We have to use this slightly awkward for loop since uint32_t >= 0 is an
|
||||
// error for being always true.
|
||||
for (uint32_t i = mFormData.Length(); i-- > 0; ) {
|
||||
if (aName.Equals(mFormData[i].name)) {
|
||||
if (lastFoundTuple) {
|
||||
// The one we found earlier was not the first one, we can remove it.
|
||||
mFormData.RemoveElementAt(lastFoundIndex);
|
||||
}
|
||||
|
||||
lastFoundTuple = &mFormData[i];
|
||||
lastFoundIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
return lastFoundTuple;
|
||||
}
|
||||
|
||||
void
|
||||
nsFormData::Set(const nsAString& aName, File& aBlob,
|
||||
const Optional<nsAString>& aFilename)
|
||||
{
|
||||
FormDataTuple* tuple = RemoveAllOthersAndGetFirstFormDataTuple(aName);
|
||||
if (tuple) {
|
||||
nsAutoString filename;
|
||||
if (aFilename.WasPassed()) {
|
||||
filename = aFilename.Value();
|
||||
} else {
|
||||
filename.SetIsVoid(true);
|
||||
}
|
||||
|
||||
SetNameFilePair(tuple, aName, &aBlob, filename);
|
||||
} else {
|
||||
Append(aName, aBlob, aFilename);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsFormData::Set(const nsAString& aName, const nsAString& aValue)
|
||||
{
|
||||
FormDataTuple* tuple = RemoveAllOthersAndGetFirstFormDataTuple(aName);
|
||||
if (tuple) {
|
||||
SetNameValuePair(tuple, aName, aValue);
|
||||
} else {
|
||||
Append(aName, aValue);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// nsIDOMFormData
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/FormDataBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
class ErrorResult;
|
||||
@ -29,8 +30,48 @@ class nsFormData MOZ_FINAL : public nsIDOMFormData,
|
||||
public nsFormSubmission,
|
||||
public nsWrapperCache
|
||||
{
|
||||
private:
|
||||
~nsFormData() {}
|
||||
|
||||
typedef mozilla::dom::File File;
|
||||
struct FormDataTuple
|
||||
{
|
||||
nsString name;
|
||||
nsString stringValue;
|
||||
nsRefPtr<File> fileValue;
|
||||
nsString filename;
|
||||
bool valueIsFile;
|
||||
};
|
||||
|
||||
// Returns the FormDataTuple to modify. This may be null, in which case
|
||||
// no element with aName was found.
|
||||
FormDataTuple*
|
||||
RemoveAllOthersAndGetFirstFormDataTuple(const nsAString& aName);
|
||||
|
||||
void SetNameValuePair(FormDataTuple* aData,
|
||||
const nsAString& aName,
|
||||
const nsAString& aValue)
|
||||
{
|
||||
MOZ_ASSERT(aData);
|
||||
aData->name = aName;
|
||||
aData->stringValue = aValue;
|
||||
aData->valueIsFile = false;
|
||||
}
|
||||
|
||||
void SetNameFilePair(FormDataTuple* aData,
|
||||
const nsAString& aName,
|
||||
File* aBlob,
|
||||
const nsAString& aFilename)
|
||||
{
|
||||
MOZ_ASSERT(aData);
|
||||
aData->name = aName;
|
||||
aData->fileValue = aBlob;
|
||||
aData->filename = aFilename;
|
||||
aData->valueIsFile = true;
|
||||
}
|
||||
|
||||
void ExtractValue(const FormDataTuple& aTuple,
|
||||
mozilla::dom::OwningFileOrUSVString* aOutValue);
|
||||
public:
|
||||
explicit nsFormData(nsISupports* aOwner = nullptr);
|
||||
|
||||
@ -55,8 +96,15 @@ public:
|
||||
const mozilla::dom::Optional<mozilla::dom::NonNull<mozilla::dom::HTMLFormElement> >& aFormElement,
|
||||
mozilla::ErrorResult& aRv);
|
||||
void Append(const nsAString& aName, const nsAString& aValue);
|
||||
void Append(const nsAString& aName, mozilla::dom::File& aBlob,
|
||||
void Append(const nsAString& aName, File& aBlob,
|
||||
const mozilla::dom::Optional<nsAString>& aFilename);
|
||||
void Delete(const nsAString& aName);
|
||||
void Get(const nsAString& aName, mozilla::dom::Nullable<mozilla::dom::OwningFileOrUSVString>& aOutValue);
|
||||
void GetAll(const nsAString& aName, nsTArray<mozilla::dom::OwningFileOrUSVString>& aValues);
|
||||
bool Has(const nsAString& aName);
|
||||
void Set(const nsAString& aName, File& aBlob,
|
||||
const mozilla::dom::Optional<nsAString>& aFilename);
|
||||
void Set(const nsAString& aName, const nsAString& aValue);
|
||||
|
||||
// nsFormSubmission
|
||||
virtual nsresult GetEncodedSubmission(nsIURI* aURI,
|
||||
@ -65,35 +113,20 @@ public:
|
||||
const nsAString& aValue) MOZ_OVERRIDE
|
||||
{
|
||||
FormDataTuple* data = mFormData.AppendElement();
|
||||
data->name = aName;
|
||||
data->stringValue = aValue;
|
||||
data->valueIsFile = false;
|
||||
SetNameValuePair(data, aName, aValue);
|
||||
return NS_OK;
|
||||
}
|
||||
virtual nsresult AddNameFilePair(const nsAString& aName,
|
||||
nsIDOMBlob* aBlob,
|
||||
File* aBlob,
|
||||
const nsString& aFilename) MOZ_OVERRIDE
|
||||
{
|
||||
FormDataTuple* data = mFormData.AppendElement();
|
||||
data->name = aName;
|
||||
data->fileValue = aBlob;
|
||||
data->filename = aFilename;
|
||||
data->valueIsFile = true;
|
||||
SetNameFilePair(data, aName, aBlob, aFilename);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsISupports> mOwner;
|
||||
|
||||
struct FormDataTuple
|
||||
{
|
||||
nsString name;
|
||||
nsString stringValue;
|
||||
nsCOMPtr<nsIDOMBlob> fileValue;
|
||||
nsString filename;
|
||||
bool valueIsFile;
|
||||
};
|
||||
|
||||
nsTArray<FormDataTuple> mFormData;
|
||||
};
|
||||
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
#include "mozilla/dom/EncodingUtils.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using mozilla::dom::EncodingUtils;
|
||||
@ -78,7 +79,7 @@ public:
|
||||
virtual nsresult AddNameValuePair(const nsAString& aName,
|
||||
const nsAString& aValue);
|
||||
virtual nsresult AddNameFilePair(const nsAString& aName,
|
||||
nsIDOMBlob* aBlob,
|
||||
File* aBlob,
|
||||
const nsString& aFilename);
|
||||
virtual nsresult GetEncodedSubmission(nsIURI* aURI,
|
||||
nsIInputStream** aPostDataStream);
|
||||
@ -165,7 +166,7 @@ nsFSURLEncoded::AddIsindex(const nsAString& aValue)
|
||||
|
||||
nsresult
|
||||
nsFSURLEncoded::AddNameFilePair(const nsAString& aName,
|
||||
nsIDOMBlob* aBlob,
|
||||
File* aBlob,
|
||||
const nsString& aFilename)
|
||||
{
|
||||
if (!mWarnedFileControl) {
|
||||
@ -174,9 +175,8 @@ nsFSURLEncoded::AddNameFilePair(const nsAString& aName,
|
||||
}
|
||||
|
||||
nsAutoString filename;
|
||||
nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
|
||||
if (file) {
|
||||
file->GetName(filename);
|
||||
if (aBlob && aBlob->IsFile()) {
|
||||
aBlob->GetName(filename);
|
||||
}
|
||||
|
||||
return AddNameValuePair(aName, filename);
|
||||
@ -441,7 +441,7 @@ nsFSMultipartFormData::AddNameValuePair(const nsAString& aName,
|
||||
|
||||
nsresult
|
||||
nsFSMultipartFormData::AddNameFilePair(const nsAString& aName,
|
||||
nsIDOMBlob* aBlob,
|
||||
File* aBlob,
|
||||
const nsString& aFilename)
|
||||
{
|
||||
// Encode the control name
|
||||
@ -459,9 +459,8 @@ nsFSMultipartFormData::AddNameFilePair(const nsAString& aName,
|
||||
} else {
|
||||
// Get and encode the filename
|
||||
nsAutoString filename16;
|
||||
nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
|
||||
if (file) {
|
||||
rv = file->GetName(filename16);
|
||||
if (aBlob->IsFile()) {
|
||||
rv = aBlob->GetName(filename16);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
@ -469,7 +468,7 @@ nsFSMultipartFormData::AddNameFilePair(const nsAString& aName,
|
||||
filename16.AssignLiteral("blob");
|
||||
} else {
|
||||
nsAutoString filepath16;
|
||||
rv = file->GetPath(filepath16);
|
||||
rv = aBlob->GetPath(filepath16);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!filepath16.IsEmpty()) {
|
||||
// File.path includes trailing "/"
|
||||
@ -598,7 +597,7 @@ public:
|
||||
virtual nsresult AddNameValuePair(const nsAString& aName,
|
||||
const nsAString& aValue);
|
||||
virtual nsresult AddNameFilePair(const nsAString& aName,
|
||||
nsIDOMBlob* aBlob,
|
||||
File* aBlob,
|
||||
const nsString& aFilename);
|
||||
virtual nsresult GetEncodedSubmission(nsIURI* aURI,
|
||||
nsIInputStream** aPostDataStream);
|
||||
@ -622,13 +621,12 @@ nsFSTextPlain::AddNameValuePair(const nsAString& aName,
|
||||
|
||||
nsresult
|
||||
nsFSTextPlain::AddNameFilePair(const nsAString& aName,
|
||||
nsIDOMBlob* aBlob,
|
||||
File* aBlob,
|
||||
const nsString& aFilename)
|
||||
{
|
||||
nsAutoString filename;
|
||||
nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
|
||||
if (file) {
|
||||
file->GetName(filename);
|
||||
if (aBlob && aBlob->IsFile()) {
|
||||
aBlob->GetName(filename);
|
||||
}
|
||||
|
||||
AddNameValuePair(aName, filename);
|
||||
|
@ -20,7 +20,12 @@ class nsIDocShell;
|
||||
class nsIRequest;
|
||||
class nsISaveAsCharset;
|
||||
class nsIMultiplexInputStream;
|
||||
class nsIDOMBlob;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class File;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
/**
|
||||
* Class for form submissions; encompasses the function to call to submit as
|
||||
@ -51,9 +56,9 @@ public:
|
||||
* @param aFilename the filename to be used (not void)
|
||||
*/
|
||||
virtual nsresult AddNameFilePair(const nsAString& aName,
|
||||
nsIDOMBlob* aBlob,
|
||||
mozilla::dom::File* aBlob,
|
||||
const nsString& aFilename) = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Reports whether the instance supports AddIsindex().
|
||||
*
|
||||
@ -161,7 +166,7 @@ public:
|
||||
virtual nsresult AddNameValuePair(const nsAString& aName,
|
||||
const nsAString& aValue) MOZ_OVERRIDE;
|
||||
virtual nsresult AddNameFilePair(const nsAString& aName,
|
||||
nsIDOMBlob* aBlob,
|
||||
mozilla::dom::File* aBlob,
|
||||
const nsString& aFilename) MOZ_OVERRIDE;
|
||||
virtual nsresult GetEncodedSubmission(nsIURI* aURI,
|
||||
nsIInputStream** aPostDataStream) MOZ_OVERRIDE;
|
||||
|
@ -14,7 +14,90 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=690659
|
||||
<script type="text/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function runTest() {
|
||||
function testHas() {
|
||||
var f = new FormData();
|
||||
f.append("foo", "bar");
|
||||
f.append("another", "value");
|
||||
ok(f.has("foo"), "has() on existing name should be true.");
|
||||
ok(f.has("another"), "has() on existing name should be true.");
|
||||
ok(!f.has("nonexistent"), "has() on non-existent name should be false.");
|
||||
}
|
||||
|
||||
function testGet() {
|
||||
var f = new FormData();
|
||||
f.append("foo", "bar");
|
||||
f.append("foo", "bar2");
|
||||
f.append("blob", new Blob(["hey"], { type: 'text/plain' }));
|
||||
f.append("file", new File(["hey"], 'testname', {type: 'text/plain'}));
|
||||
|
||||
is(f.get("foo"), "bar", "get() on existing name should return first value");
|
||||
ok(f.get("blob") instanceof Blob, "get() on existing name should return first value");
|
||||
is(f.get("blob").type, 'text/plain', "get() on existing name should return first value");
|
||||
ok(f.get("file") instanceof File, "get() on existing name should return first value");
|
||||
is(f.get("file").name, 'testname', "get() on existing name should return first value");
|
||||
|
||||
is(f.get("nonexistent"), null, "get() on non-existent name should return null.");
|
||||
}
|
||||
|
||||
function testGetAll() {
|
||||
var f = new FormData();
|
||||
f.append("other", "value");
|
||||
f.append("foo", "bar");
|
||||
f.append("foo", "bar2");
|
||||
f.append("foo", new Blob(["hey"], { type: 'text/plain' }));
|
||||
|
||||
var arr = f.getAll("foo");
|
||||
is(arr.length, 3, "getAll() should retrieve all matching entries.");
|
||||
is(arr[0], "bar", "values should match and be in order");
|
||||
is(arr[1], "bar2", "values should match and be in order");
|
||||
ok(arr[2] instanceof Blob, "values should match and be in order");
|
||||
|
||||
is(f.get("nonexistent"), null, "get() on non-existent name should return null.");
|
||||
}
|
||||
|
||||
function testDelete() {
|
||||
var f = new FormData();
|
||||
f.append("other", "value");
|
||||
f.append("foo", "bar");
|
||||
f.append("foo", "bar2");
|
||||
f.append("foo", new Blob(["hey"], { type: 'text/plain' }));
|
||||
|
||||
ok(f.has("foo"), "has() on existing name should be true.");
|
||||
f.delete("foo");
|
||||
ok(!f.has("foo"), "has() on deleted name should be false.");
|
||||
is(f.getAll("foo").length, 0, "all entries should be deleted.");
|
||||
|
||||
is(f.getAll("other").length, 1, "other names should still be there.");
|
||||
f.delete("other");
|
||||
is(f.getAll("other").length, 0, "all entries should be deleted.");
|
||||
}
|
||||
|
||||
function testSet() {
|
||||
var f = new FormData();
|
||||
|
||||
f.set("other", "value");
|
||||
ok(f.has("other"), "set() on new name should be similar to append()");
|
||||
is(f.getAll("other").length, 1, "set() on new name should be similar to append()");
|
||||
|
||||
f.append("other", "value2");
|
||||
is(f.getAll("other").length, 2, "append() should not replace existing entries.");
|
||||
|
||||
f.append("foo", "bar");
|
||||
f.append("other", "value3");
|
||||
f.append("other", "value3");
|
||||
f.append("other", "value3");
|
||||
is(f.getAll("other").length, 5, "append() should not replace existing entries.");
|
||||
|
||||
f.set("other", "value4");
|
||||
is(f.getAll("other").length, 1, "set() should replace existing entries.");
|
||||
is(f.getAll("other")[0], "value4", "set() should replace existing entries.");
|
||||
}
|
||||
|
||||
function testIterate() {
|
||||
todo(false, "Implement this in Bug 1085284.");
|
||||
}
|
||||
|
||||
function testSend() {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "form_submit_server.sjs");
|
||||
xhr.onload = function () {
|
||||
@ -62,6 +145,17 @@ function runTest() {
|
||||
xhr.send(fd);
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
testHas();
|
||||
testGet();
|
||||
testGetAll();
|
||||
testDelete();
|
||||
testSet();
|
||||
testIterate();
|
||||
// Finally, send an XHR and verify the response matches.
|
||||
testSend();
|
||||
}
|
||||
|
||||
runTest()
|
||||
</script>
|
||||
</body>
|
||||
|
@ -7,8 +7,17 @@
|
||||
* http://xhr.spec.whatwg.org
|
||||
*/
|
||||
|
||||
typedef (File or USVString) FormDataEntryValue;
|
||||
|
||||
[Constructor(optional HTMLFormElement form)]
|
||||
interface FormData {
|
||||
void append(DOMString name, Blob value, optional DOMString filename);
|
||||
void append(DOMString name, DOMString value);
|
||||
void append(USVString name, Blob value, optional USVString filename);
|
||||
void append(USVString name, USVString value);
|
||||
void delete(USVString name);
|
||||
FormDataEntryValue? get(USVString name);
|
||||
sequence<FormDataEntryValue> getAll(USVString name);
|
||||
boolean has(USVString name);
|
||||
void set(USVString name, Blob value, optional USVString filename);
|
||||
void set(USVString name, USVString value);
|
||||
// iterable<USVString, FormDataEntryValue>; - Bug 1127703
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user