Bug 1237595 - FormData ctor and form submission should create empty Blob/File when a input type=file is not set, r=smaug

This commit is contained in:
Andrea Marchesini 2016-01-08 08:35:30 +00:00
Родитель d7f8317f74
Коммит d64cfad447
7 изменённых файлов: 123 добавлений и 67 удалений

Просмотреть файл

@ -957,6 +957,32 @@ BlobImplFile::LookupAndCacheIsDirectory()
mDirState = isDir ? BlobDirState::eIsDir : BlobDirState::eIsNotDir;
}
////////////////////////////////////////////////////////////////////////////
// BlobImplEmptyFile implementation
NS_IMPL_ISUPPORTS_INHERITED0(BlobImplEmptyFile, BlobImpl)
already_AddRefed<BlobImpl>
BlobImplEmptyFile::CreateSlice(uint64_t aStart, uint64_t aLength,
const nsAString& aContentType,
ErrorResult& aRv)
{
MOZ_ASSERT(!aStart && !aLength);
RefPtr<BlobImpl> impl = new BlobImplEmptyFile(aContentType);
return impl.forget();
}
void
BlobImplEmptyFile::GetInternalStream(nsIInputStream** aStream,
ErrorResult& aRv)
{
nsresult rv = NS_NewCStringInputStream(aStream, EmptyCString());
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(rv);
return;
}
}
////////////////////////////////////////////////////////////////////////////
// BlobImplMemory implementation

Просмотреть файл

@ -833,6 +833,31 @@ private:
bool mIsTemporary;
};
class BlobImplEmptyFile final : public BlobImplBase
{
public:
NS_DECL_ISUPPORTS_INHERITED
explicit BlobImplEmptyFile(const nsAString& aContentType)
: BlobImplBase(EmptyString(), aContentType, 0 /* aLength */)
{}
virtual void GetInternalStream(nsIInputStream** aStream,
ErrorResult& aRv) override;
virtual already_AddRefed<BlobImpl>
CreateSlice(uint64_t aStart, uint64_t aLength,
const nsAString& aContentType, ErrorResult& aRv) override;
virtual bool IsMemoryFile() const override
{
return true;
}
private:
~BlobImplEmptyFile() {}
};
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -179,6 +179,8 @@ FormData::Has(const nsAString& aName)
nsresult
FormData::AddNameFilePair(const nsAString& aName, File* aFile)
{
MOZ_ASSERT(aFile);
FormDataTuple* data = mFormData.AppendElement();
SetNameFilePair(data, aName, aFile);
return NS_OK;
@ -272,12 +274,10 @@ FormData::SetNameFilePair(FormDataTuple* aData,
File* aFile)
{
MOZ_ASSERT(aData);
MOZ_ASSERT(aFile);
aData->name = aName;
if (aFile) {
aData->value.SetAsFile() = aFile;
} else {
aData->value.SetAsUSVString() = EmptyString();
}
aData->value.SetAsFile() = aFile;
}
// -------------------------------------------------------------------------
@ -364,7 +364,7 @@ FormData::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength,
fs.AddNameValuePair(mFormData[i].name,
mFormData[i].value.GetAsUSVString());
} else {
fs.AddNameFilePair(mFormData[i].name, nullptr);
MOZ_CRASH("This should no be possible.");
}
}

Просмотреть файл

@ -14,7 +14,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=789315
<form id="a"><input name="b" type="file"/></form>
<script type="text/javascript">
is(new FormData(document.getElementById('a')).get('b'), "", "This should return an empty string.");
var obj = new FormData(document.getElementById('a')).get('b');
ok(obj instanceof File, "This should return an empty File");
is(obj.size, 0, "Size should be 0");
is(obj.name, "", "Name should be an empty string");
is(obj.type, "application/octet-stream", "Type should be application/octet-stream");
var o = obj.slice(10, 100, "foo/bar");
is(o.size, 0, "The new blob has size 0");
is(o.type, "foo/bar", "The new blob has type foo/bar");
</script>
</body>

Просмотреть файл

@ -5593,9 +5593,10 @@ HTMLInputElement::SubmitNamesValues(nsFormSubmission* aFormSubmission)
}
if (files.IsEmpty()) {
// If no file was selected, pretend we had an empty file with an
// empty filename.
aFormSubmission->AddNameFilePair(name, nullptr);
RefPtr<BlobImpl> blobImpl =
new BlobImplEmptyFile(NS_LITERAL_STRING("application/octet-stream"));
RefPtr<File> file = File::Create(OwnerDoc()->GetInnerWindow(), blobImpl);
aFormSubmission->AddNameFilePair(name, file);
}
return NS_OK;

Просмотреть файл

@ -167,15 +167,15 @@ nsresult
nsFSURLEncoded::AddNameFilePair(const nsAString& aName,
File* aFile)
{
MOZ_ASSERT(aFile);
if (!mWarnedFileControl) {
SendJSWarning(mDocument, "ForgotFileEnctypeWarning", nullptr, 0);
mWarnedFileControl = true;
}
nsAutoString filename;
if (aFile) {
aFile->GetName(filename);
}
aFile->GetName(filename);
return AddNameValuePair(aName, filename);
}
@ -441,61 +441,60 @@ nsresult
nsFSMultipartFormData::AddNameFilePair(const nsAString& aName,
File* aFile)
{
MOZ_ASSERT(aFile);
// Encode the control name
nsAutoCString nameStr;
nsresult rv = EncodeVal(aName, nameStr, true);
NS_ENSURE_SUCCESS(rv, rv);
nsCString filename, contentType;
nsAutoString filename16;
aFile->GetName(filename16);
ErrorResult error;
nsAutoString filepath16;
aFile->GetPath(filepath16, error);
if (NS_WARN_IF(error.Failed())) {
return error.StealNSResult();
}
if (!filepath16.IsEmpty()) {
// File.path includes trailing "/"
filename16 = filepath16 + filename16;
}
nsAutoCString filename;
rv = EncodeVal(filename16, filename, true);
NS_ENSURE_SUCCESS(rv, rv);
// Get content type
nsAutoString contentType16;
aFile->GetType(contentType16);
if (contentType16.IsEmpty()) {
contentType16.AssignLiteral("application/octet-stream");
}
nsAutoCString contentType;
contentType.Adopt(nsLinebreakConverter::
ConvertLineBreaks(NS_ConvertUTF16toUTF8(contentType16).get(),
nsLinebreakConverter::eLinebreakAny,
nsLinebreakConverter::eLinebreakSpace));
// Get input stream
nsCOMPtr<nsIInputStream> fileStream;
if (aFile) {
nsAutoString filename16;
aFile->GetName(filename16);
aFile->GetInternalStream(getter_AddRefs(fileStream), error);
if (NS_WARN_IF(error.Failed())) {
return error.StealNSResult();
}
ErrorResult error;
nsAutoString filepath16;
aFile->GetPath(filepath16, error);
if (NS_WARN_IF(error.Failed())) {
return error.StealNSResult();
}
if (!filepath16.IsEmpty()) {
// File.path includes trailing "/"
filename16 = filepath16 + filename16;
}
rv = EncodeVal(filename16, filename, true);
if (fileStream) {
// Create buffered stream (for efficiency)
nsCOMPtr<nsIInputStream> bufferedStream;
rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream),
fileStream, 8192);
NS_ENSURE_SUCCESS(rv, rv);
// Get content type
nsAutoString contentType16;
aFile->GetType(contentType16);
if (contentType16.IsEmpty()) {
contentType16.AssignLiteral("application/octet-stream");
}
contentType.Adopt(nsLinebreakConverter::
ConvertLineBreaks(NS_ConvertUTF16toUTF8(contentType16).get(),
nsLinebreakConverter::eLinebreakAny,
nsLinebreakConverter::eLinebreakSpace));
// Get input stream
aFile->GetInternalStream(getter_AddRefs(fileStream), error);
if (NS_WARN_IF(error.Failed())) {
return error.StealNSResult();
}
if (fileStream) {
// Create buffered stream (for efficiency)
nsCOMPtr<nsIInputStream> bufferedStream;
rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream),
fileStream, 8192);
NS_ENSURE_SUCCESS(rv, rv);
fileStream = bufferedStream;
}
}
else {
contentType.AssignLiteral("application/octet-stream");
fileStream = bufferedStream;
}
//
@ -619,9 +618,7 @@ nsFSTextPlain::AddNameFilePair(const nsAString& aName,
File* aFile)
{
nsAutoString filename;
if (aFile) {
aFile->GetName(filename);
}
aFile->GetName(filename);
AddNameValuePair(aName, filename);
return NS_OK;

Просмотреть файл

@ -258,7 +258,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=523771
<p>
File input:
<input type=file name="file_1" class="setfile">
<input type=file name="file_2" class="setfile empty">
<input type=file name="file_2">
<input type=file name="" class="setfile">
<input type=file name="">
<input type=file class="setfile">
@ -268,7 +268,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=523771
Multifile input:
<input multiple type=file name="file_3" class="setfile">
<input multiple type=file name="file_4" class="setfile multi">
<input multiple type=file name="file_5" class="setfile empty">
<input multiple type=file name="file_5">
<input multiple type=file name="" class="setfile">
<input multiple type=file name="" class="setfile multi">
<input multiple type=file name="">
@ -426,7 +426,6 @@ function onFilesOpened(files) {
let singleFile = textFile;
let multiFile = [textFile, imageFile];
emptyFile = new File([], "", { type: "application/octet-stream" });
var addList = document.getElementsByClassName("setfile");
let i = 0;
@ -434,8 +433,6 @@ function onFilesOpened(files) {
while (input = addList[i++]) {
if (input.classList.contains("multi")) {
SpecialPowers.wrap(input).mozSetFileArray(multiFile);
} else if (input.classList.contains("empty")) {
SpecialPowers.wrap(input).mozSetFileArray([emptyFile]);
} else {
SpecialPowers.wrap(input).mozSetFileArray([singleFile]);
}
@ -449,6 +446,7 @@ function onFilesOpened(files) {
myFile2 = input.files[1];
is(myFile1.size, 20, "File1 size");
is(myFile2.size, 2711, "File2 size");
emptyFile = { name: "", type: "application/octet-stream" };
// Now, actually run the tests; see below.
onFilesSet();